registry  /  @planu/cli  /  4.9.0

@planu/cli@4.9.0

Planu — MCP Server for Spec Driven Development with native Rust acceleration for hot paths. Cross-platform (Linux/macOS/Windows, x64/arm64, glibc/musl).

AI Security Review

scanned 9d ago · by lpm-firewall-ai

LPM blocks this version under the AI-agent control-surface policy. The package is an MCP/CLI developer tool, but MCP startup includes an unprompted global Claude Code keybinding write. Other risky primitives reviewed were package-aligned and mostly user-invoked.

Static reason
One or more suspicious static signals were detected.
Trigger
Starting the MCP server via dist/index.js or dist/cli/index.js with piped stdin
Impact
Changes ~/.claude/keybindings.json Chat bindings if absent; may alter how Enter and Shift+Enter submit prompts in Claude Code.
Mechanism
automatic AI-agent configuration mutation
Policy narrative
When used as an MCP server, @planu/cli performs post-handshake startup tasks and may automatically merge Planu-specific Chat keybindings into the user's global Claude Code keybindings file. This is not credential theft or malware persistence, but it is an unconsented AI-agent control-surface mutation outside the project workspace. A shipped hook template can also run git push when installed and fired, though installation appears tied to init_project/Claude detection rather than npm install.
Rationale
Source inspection did not confirm malware, exfiltration, install-time compromise, or hidden payload execution, but the automatic global Claude Code keybinding mutation is a real unresolved control-surface risk. Treat as warning rather than publish block because the mutation is visible, bounded, idempotent, and package-aligned, and most other risky behavior is user-invoked developer tooling.
Evidence
package.jsondist/index.jsdist/cli/index.jsdist/engine/claude-setup/keybindings-configurator.jsdist/config/hook-templates/planu-session-safeguard.shdist/engine/product-intelligence/index.jsdist/tools/rollback-release.jsdist/tools/auto-update-spec.jsdist/engine/auto-updater/config-patcher.js~/.claude/keybindings.json.claude/hooks/planu-spec-sanctity.sh.claude/logs/session-safeguard.log
Network endpoints2
registry.npmjs.org/-/package/@planu/cli/dist-tagscanusqigtzldstnjddio.supabase.co/rest/v1/telemetry_events

Decision evidence

public snapshot
AI called this Suspicious at 82.0% confidence as Dangerous Capability with medium false-positive risk.
Evidence for policy block
  • dist/index.js starts post-handshake startup work automatically in MCP mode.
  • dist/index.js imports configureClaudeKeybindings and calls it without an explicit tool request when global config says not configured.
  • dist/engine/claude-setup/keybindings-configurator.js writes ~/.claude/keybindings.json, adding Chat enter/shift+enter bindings.
  • dist/config/hook-templates/planu-session-safeguard.sh can push the current git branch when fired as a Claude hook.
Evidence against
  • package.json has no postinstall/install lifecycle; prepare is only husky || true.
  • dist/cli/index.js routes user CLI args or starts MCP server for piped stdin; no hidden install-time execution found.
  • dist/tools/rollback-release.js npm/npx child_process use is confined to rollback_release handler, not import-time.
  • dist/tools/auto-update-spec.js git diff is a user-invoked spec update helper.
  • dist/engine/product-intelligence/index.js queries a package-aligned Supabase telemetry table with an anon key, not credential harvesting.
  • dist/engine/auto-updater/config-patcher.js requires confirm=true before patching MCP config.
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsEvalFilesystemNetworkShellWebSocket
Supply chain
HighEntropyStringsTelemetryUrlStrings
Manifest
NoLicense
scanned 2,729 file(s), 9.98 MB of source, external domains: agentskill.sh, api.anthropic.com, api.cloudflare.com, api.example.com, api.figma.com, api.github.com, api.linear.app, api.machines.dev, api.mistral.ai, api.netlify.com, api.notion.com, api.npmjs.org, api.nuget.org, api.openai.com, api.osv.dev, api.supabase.com, api.trello.com, api.vercel.com, app.mem0.ai, argocd-applicationset.readthedocs.io, azure.microsoft.com, backboard.railway.app, backstage.io, bentoml.com, bit.dev, canusqigtzldstnjddio.supabase.co, cdn.jsdelivr.net, chaos.cncf.io, checkstyle.sourceforge.io, clang.llvm.org, claude.ai, cloud.google.com, code.claude.com, commitlint.js.org, conftest.dev, containers.dev, cortex.io, cppcheck.sourceforge.io, crates.io, crossplane.io, cs.symfony.com, cursor.com, cyclonedx.org, daggerverse.dev, dart.dev, detekt.dev, developer.android.com, dl.dagger.io, doc.rust-lang.org, doc.traefik.io

Source & flagged code

14 flagged · loading source
dist/engine/product-intelligence/index.jsView file
7patternName = supabase_service_key severity = critical line = 7 matchedText = 'eyJhbGc...MU';
Critical
Critical Secret

Package contains a critical-looking secret pattern.

dist/engine/product-intelligence/index.jsView on unpkg · L7
7patternName = supabase_service_key severity = critical line = 7 matchedText = 'eyJhbGc...MU';
Critical
Secret Pattern

Supabase service role key (JWT) in dist/engine/product-intelligence/index.js

dist/engine/product-intelligence/index.jsView on unpkg · L7
dist/tools/auto-update-spec.jsView file
1// tools/auto-update-spec.ts — auto_update_spec handler (SPEC-170) L2: import { execFile } from 'node:child_process'; L3: import { promisify } from 'node:util';
High
Child Process

Package source references child process execution.

dist/tools/auto-update-spec.jsView on unpkg · L1
dist/engine/verifier/code-scanner.jsView file
5import { glob } from 'glob'; L6: const execAsync = promisify(exec); L7: const SOURCE_GLOBS = ['**/*.ts', '**/*.js', '**/*.py', '**/*.go', '**/*.java', '**/*.rs'];
High
Shell

Package source references shell execution.

dist/engine/verifier/code-scanner.jsView on unpkg · L5
dist/engine/auditor-security/electron-checks.jsView file
74rule: 'electron-eval-in-renderer', L75: message: 'eval() in Electron renderer enables remote code execution if XSS is present.', L76: suggestion: 'Remove all eval() calls. Use JSON.parse() or safer alternatives.',
Low
Eval

Package source references a known benign dynamic code generation pattern.

dist/engine/auditor-security/electron-checks.jsView on unpkg · L74
dist/tools/import-spec-handler.jsView file
148*/ L149: export async function handleBulkImport(params) { L150: const { source, filePath, content, projectPath, overwrite = false } = params;
Medium
Dynamic Require

Package source references dynamic require/import behavior.

dist/tools/import-spec-handler.jsView on unpkg · L148
dist/engine/delete-first/duplication-finder.jsView file
1// Planu — Duplication finder (SPEC-482) L2: // Hash-compares normalized code blocks with a sliding window to detect copy-paste.
Low
Weak Crypto

Package source references weak cryptographic algorithms.

dist/engine/delete-first/duplication-finder.jsView on unpkg · L1
dist/tools/rollback-release.jsView file
48return new Promise((resolve) => { L49: const child = spawn('npx', ['--yes', '@planu/cli@latest', '--version'], { L50: stdio: ['ignore', 'pipe', 'pipe'],
High
Runtime Package Install

Package source invokes a package manager install command at runtime.

dist/tools/rollback-release.jsView on unpkg · L48
dist/config/hook-templates/planu-session-safeguard.shView file
path = dist/config/hook-templates/planu-session-safeguard.sh kind = build_helper sizeBytes = 535 magicHex = [redacted]
Medium
Ships Build Helper

Package ships non-JavaScript build or shell helper files.

dist/config/hook-templates/planu-session-safeguard.shView on unpkg
dist/config/mobile-ci-templates/android-github-actions.ymlView file
88patternName = generic_password severity = medium line = 88 matchedText = -Pandroi...D" \
Medium
Secret Pattern

Hardcoded password in dist/config/mobile-ci-templates/android-github-actions.yml

dist/config/mobile-ci-templates/android-github-actions.ymlView on unpkg · L88
90patternName = generic_password severity = medium line = 90 matchedText = -Pandroi...ORD"
Medium
Secret Pattern

Hardcoded password in dist/config/mobile-ci-templates/android-github-actions.yml

dist/config/mobile-ci-templates/android-github-actions.ymlView on unpkg · L90
dist/engine/ci-generator/android-jobs.jsView file
95patternName = generic_password severity = medium line = 95 matchedText = ` -Pand...\\`,
Medium
Secret Pattern

Hardcoded password in dist/engine/ci-generator/android-jobs.js

dist/engine/ci-generator/android-jobs.jsView on unpkg · L95
97patternName = generic_password severity = medium line = 97 matchedText = ` -Pand...D"`,
Medium
Secret Pattern

Hardcoded password in dist/engine/ci-generator/android-jobs.js

dist/engine/ci-generator/android-jobs.jsView on unpkg · L97
dist/engine/telemetry/telemetry-client.jsView file
5patternName = supabase_service_key severity = critical line = 5 matchedText = const SU...MU';
Critical
Secret Pattern

Supabase service role key (JWT) in dist/engine/telemetry/telemetry-client.js

dist/engine/telemetry/telemetry-client.jsView on unpkg · L5

Findings

3 Critical3 High9 Medium9 Low
CriticalCritical Secretdist/engine/product-intelligence/index.js
CriticalSecret Patterndist/engine/product-intelligence/index.js
CriticalSecret Patterndist/engine/telemetry/telemetry-client.js
HighChild Processdist/tools/auto-update-spec.js
HighShelldist/engine/verifier/code-scanner.js
HighRuntime Package Installdist/tools/rollback-release.js
MediumDynamic Requiredist/tools/import-spec-handler.js
MediumNetwork
MediumEnvironment Vars
MediumShips Build Helperdist/config/hook-templates/planu-session-safeguard.sh
MediumStructural Risk Force Deep Review
MediumSecret Patterndist/config/mobile-ci-templates/android-github-actions.yml
MediumSecret Patterndist/config/mobile-ci-templates/android-github-actions.yml
MediumSecret Patterndist/engine/ci-generator/android-jobs.js
MediumSecret Patterndist/engine/ci-generator/android-jobs.js
LowNon Install Lifecycle Scripts
LowScripts Present
LowEvaldist/engine/auditor-security/electron-checks.js
LowWeak Cryptodist/engine/delete-first/duplication-finder.js
LowFilesystem
LowHigh Entropy Strings
LowTelemetry
LowUrl Strings
LowNo License