SkillTotal

Is Storybloq safe?

No malicious indicators - review capabilities before installing
Notable — review in context (capabilities are not malware):
  • Node.js shell/command execution
  • Dangerous MCP tool capability
  • Node.js filesystem read

@storybloq/storybloq is an AI npm_package analyzed by SkillTotal's deterministic static scanner. The scan found no malicious indicators, though 6 risky constructs are reported for review. It can: filesystem read, filesystem write, mcp tools detected, network egress and shell execution — capabilities are what the code can do, not a verdict on intent. Risk score 0/100 (low).

@storybloq/storybloq 1.9.0

npm_package · https://github.com/Storybloq/storybloq
LOW
0
/ 100 risk score
Snapshot · scanned Aug 10, 2026 · @storybloq/storybloq@1.9.0 · engine 0.38.1 / ruleset 42

Automated static-analysis result. It can contain false positives and false negatives, and is not a claim about the intent of Storybloq's authors. Report a false positive.

Capabilities — what this component can do (not a risk score):
filesystem readfilesystem writemcp tools detectednetwork egressshell execution

Behavioral traits

How this component maps to the CSA agentic threat model. Descriptive — it never affects the risk score.

Tool surface
Tool Usage
Execution authority
Tool Access Control / Direct Tool Access
Filesystem reach
Tool Execution Context
Network egress
Interaction & Communication / Direct Communication

Findings (6)

HIGHDangerous MCP tool capabilityST-MCP-DANGEROUS-TOOL

An MCP tool exposes a powerful capability (files, shell, network, browser, or credentials).

server.registerTool("storybloq_register_subprocess", {
server.registerTool("storybloq_unregister_subprocess", {

Why it matters: Wired into an agent, these grant it real access to your machine — confirm each is required.

Fix: Confirm each powerful tool is required and constrained; broad MCP tools (shell/filesystem/network) grant an agent significant host access.

HIGHNode.js shell/command executionST-SHELL-NODE

The component can run operating-system commands or spawn processes.

import { execFileSync, spawn } from "node:child_process";
const child = spawn("claude", args, {
while ((match = ENTITY_ID_REGEX.exec(branch)) !== null) {
import { execFile } from "node:child_process";
while ((match = pattern.exec(content)) !== null) {
import { execFileSync, execSync } from "node:child_process";
import { spawn, execFileSync, type ChildProcess } from "node:child_process";
const match = /^Session:\s*(\S+)\s*$/.exec(line);
import { execFileSync } from "node:child_process";
import { spawn } from "node:child_process";
const child = spawn(cmd, args, { cwd: opts.cwd, env: opts.env, detached: true, stdio: "ignore" });
// The record moved between claim and spawn (interactive takeover, re-limit
const child = spawn(process.execPath, [bin, "waker-run", WAKER_ARGV_SENTINEL], {
// honoring it and the next hook is allowed to spawn (the fresh child's try-lock reclaims).
import { spawn as nodeSpawn } from "node:child_process";
import type { SpawnOptions } from "node:child_process";
import { execFile } from "node:child_process";
const match = ENTRY_FILENAME.exec(filename);
import { execFile } from "node:child_process";
const match = ENTRY_FILENAME.exec(filename);
const match = ENDPOINT_FILENAME.exec(entry.name);
const match = ENTRY_FILENAME.exec(filename);

Why it matters: Powerful and often legitimate — confirm the commands aren't built from untrusted input.

Fix: Confirm the command and its arguments are fully controlled and not derived from untrusted input; prefer execFile with an argument array.

MEDIUMNode.js filesystem readST-FS-NODE-READ

The component reads files from disk.

const raw = fs.readFileSync(`/proc/${pid}/stat`, "utf-8");
fs.readFileSync(join(telemetryDirPath(sessionDir), "lastMcpCall"), "utf-8").trim() || null
const val = fs.readFileSync(join(tDir, "alive"), "utf-8").trim();
raw = fs.readFileSync(join(sessionDir, "state.json"), "utf-8");
content = fs.readFileSync(alivePath, "utf-8");
raw = fs.readFileSync(p, "utf-8").trim();
const buf = fs.readFileSync(p);
existing = fs.readFileSync(gitignorePath, "utf-8");
if (fs.readFileSync(entryPath(root, pid), "utf-8") !== payload) return false;
const onDisk = parseEntry(pid, fs.readFileSync(entryPath(root, pid), "utf-8"));
entry = parseEntry(pid, fs.readFileSync(join(dir, name), "utf-8"));
raw = fs.readFileSync(statePath, "utf-8");
const raw = await import("node:fs/promises").then((fs) => fs.readFile(`/proc/${pid}/stat`, "utf-8"));
const raw = fs.readFileSync(`/proc/${pid}/stat`, "utf-8");
raw = fs.readFileSync(join(sessionDir, "state.json"), "utf-8");

Why it matters: Usually legitimate, but worth confirming it can't be steered into reading sensitive files.

Fix: Confirm which files are read and that paths cannot be influenced by untrusted input to reach sensitive locations.

MEDIUMNode.js filesystem write/deleteST-FS-NODE-WRITE

The component writes or deletes files on disk.

"  if(process.ppid!==ppid){try{fs.writeFileSync(alive,\"0\")}catch{}process.exit(0)}",
"  if(fs.existsSync(shut)){try{fs.writeFileSync(alive,\"0\")}catch{}process.exit(0)}",
"  try{fs.writeFileSync(alive,String(Date.now()))}catch{}",
try { fs.unlinkSync(lockPath); return { unlinked: true }; }
fs.writeFileSync(tmpPath, JSON.stringify(body), { mode: 0o600 });
try { fs.unlinkSync(tmpPath); }
try { fs.unlinkSync(handle.tmpPath); }
fs.writeFileSync(tmp, String(pid), { mode: 0o600 });
try { fs.unlinkSync(tmp); } catch { /* ignore */ }
try { fs.unlinkSync(join(tDir, PID_BASENAME)); }
fs.unlinkSync(join(tDir, "shutdown"));
fs.writeFileSync(join(dir, "shutdown"), "1");
fs.writeFileSync(join(dir, "alive"), "0");
fs.writeFileSync(tmp, new Date().toISOString());
try { fs.unlinkSync(join(dir, name)); } catch { /* already gone, or not a file */ }
fs.writeFileSync(gitignorePath, content, "utf-8");
fs.writeFileSync(entryPath(root, pid), payload);
fs.unlinkSync(entryPath(root, pid));
fs.writeFileSync(probe, "");
try { fs.unlinkSync(join(dir, name)); } catch { /* another process reaped it */ }
fs.unlinkSync(wakeClaimPath(sessionDir));
fs.writeFileSync(tmp, body, { mode: 0o600 });

Why it matters: Usually legitimate, but worth confirming the paths can't be controlled by untrusted input.

Fix: Confirm which files are written/deleted and that paths cannot be influenced by untrusted input.

MEDIUMNode.js network egressST-NET-NODE

The component makes outbound network requests.

* Privacy opt-out for the registry fetch (ISS-777): NO_UPDATE_NOTIFIER or CI
const res = await fetch(NPM_REGISTRY_URL, { signal: controller.signal });
response = await fetch(url, {

Why it matters: Usually legitimate, but confirm the destinations are expected and no sensitive data leaves.

Fix: Confirm the destination hosts are expected and that no sensitive data is sent off-host.

LOWMCP tool surface detectedST-MCP-DETECTED

An MCP tool surface (manifest or tool definitions) was found.

server.registerTool("storybloq_bus_send", {
server.registerTool("storybloq_bus_redeliver", {
server.registerTool("storybloq_bus_poll", {
server.registerTool("storybloq_bus_ack", {
server.registerTool("storybloq_bus_thread_get", {
server.registerTool("storybloq_bus_thread_update", {
const degradedStatus = server.registerTool("storybloq_status", {
const degradedInit = server.registerTool("storybloq_init", {
server.registerTool("storybloq_status", {
server.registerTool("storybloq_phase_list", {
server.registerTool("storybloq_phase_current", {
server.registerTool("storybloq_ticket_next", {
server.registerTool("storybloq_ticket_blocked", {
server.registerTool("storybloq_handover_list", {
server.registerTool("storybloq_handover_latest", {
server.registerTool("storybloq_blocker_list", {
server.registerTool("storybloq_validate", {
server.registerTool("storybloq_phase_tickets", {
server.registerTool("storybloq_ticket_list", {
server.registerTool("storybloq_ticket_get", {
server.registerTool("storybloq_ticket_meta_get", {
server.registerTool("storybloq_issue_list", {
server.registerTool("storybloq_issue_get", {
server.registerTool("storybloq_issue_meta_get", {
server.registerTool("storybloq_handover_get", {

Why it matters: Just context — review which tools it offers and their permissions.

Fix: Review the declared MCP tools and their permissions.

Check your own component

Run the same evidence-backed scan on any MCP server, agent skill, or package.

Scan your own component

How we determine this: deterministic static analysis (regex + AST), evidence-anchored, no code execution. Methodology →