SkillTotal

Is obra/superpowers safe?

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

superpowers 6.1.0

npm_package · https://github.com/obra/superpowers
LOW
20
/ 100 risk score
Snapshot · scanned Jul 1, 2026 · superpowers@6.1.0 · engine 0.22.0 / ruleset 23
No malicious indicators - review capabilities before installing
Notable — review in context (capabilities are not malware):
  • Node.js shell/command execution
  • Possible command injection (exec with dynamic command)
  • Node.js filesystem read

No malicious indicators found by static analysis.

Capabilities — what this component can do (not a risk score):
filesystem readfilesystem writeshell execution

Findings (4)

HIGHPossible command injection (exec with dynamic command)ST-CMDI-NODE

The code builds an OS command out of values that can change at runtime, then runs it through a shell.

try { cp.exec(process.env.BRAINSTORM_OPEN_CMD + ' ' + JSON.stringify(url), () => {}); } catch (e) { /* best effort */ }

Why it matters: If any of those values come from untrusted input, an attacker can run their own commands on the machine.

Fix: Use execFile/spawn with an argument array instead of exec; never build a shell command string from external input.

HIGHNode.js shell/command executionST-SHELL-NODE

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

const cp = require('child_process');
try { cp.exec(process.env.BRAINSTORM_OPEN_CMD + ' ' + JSON.stringify(url), () => {}); } catch (e) { /* best effort */ }
const { execSync } = require('child_process');
while ((match = regex.exec(markdown)) !== null) {
execSync('which dot', { encoding: 'utf-8' });

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 fullContent = fs.readFileSync(skillPath, 'utf8');
const p = Number(fs.readFileSync(PORT_FILE, 'utf-8').trim());
const t = fs.readFileSync(TOKEN_FILE, 'utf-8').trim();
const frameTemplate = fs.readFileSync(path.join(__dirname, 'frame-template.html'), 'utf-8');
const helperScript = fs.readFileSync(path.join(__dirname, 'helper.js'), 'utf-8');
const data = JSON.parse(fs.readFileSync(manifest, 'utf-8'));
? (raw => isFullDocument(raw) ? raw : wrapInFrame(raw))(fs.readFileSync(screenFile, 'utf-8'))
res.end(fs.readFileSync(filePath));
const markdown = fs.readFileSync(skillFile, '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.

fs.appendFileSync(eventsFile, JSON.stringify(event) + '\n');
if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile);
if (fs.existsSync(infoFile)) fs.unlinkSync(infoFile);
try { fs.writeFileSync(PORT_FILE, String(PORT)); } catch (e) { /* best effort */ }
fs.writeFileSync(TOKEN_FILE, TOKEN, { mode: 0o600 });
fs.writeFileSync(path.join(STATE_DIR, 'server-info'), info + '\n', { mode: 0o600 });
fs.writeFileSync(outputPath, svg);
fs.writeFileSync(dotPath, combined);
fs.writeFileSync(outputPath, svg);

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.

Check your own component

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

Scan your own component

Or get notified if this component's risk changes:

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