AI Security Review
scanned 3d ago · by lpm-firewall-aiInstall-time script mutates the consumer project's Claude Code control surface. It drops package-supplied skills/instructions and prepends an import into .claude/CLAUDE.md without an explicit user action beyond npm install.
Static reason
High-risk behavior combination matched malicious policy.
Trigger
npm install / postinstall
Impact
Future Claude Code sessions in the consumer project may load package-supplied instructions and skills automatically.
Mechanism
unconsented lifecycle AI-agent control-surface mutation
Attack narrative
On postinstall, scripts/setup.mjs detects installation under node_modules, uses INIT_CWD as the consumer project root, copies package-owned AI extension directories into .claude with a namespace prefix, deletes old prefixed entries, and writes a generated @import block at the top of .claude/CLAUDE.md. The content appears UI-doc oriented, but the install-time mutation of an AI agent control surface is concrete and unconsented.
Rationale
Direct source inspection confirms a postinstall hook that writes package-provided Claude control files into the consumer project. Even without exfiltration or hostile instructions, this matches the firewall policy for unconsented lifecycle AI-agent control-surface mutation. Product guard normalized a non-low false-positive publish_block request to warn-only suspicious.
Evidence
package.jsonscripts/setup.mjsai-extensions/CLAUDE.mdai-extensions/skills/ui-docs/SKILL.mdai-extensions/skills/setup-ploomes-ui/SKILL.md.claude/skills/ploomes-design-system-*.claude/agents/ploomes-design-system-*.claude/commands/ploomes-design-system-*.claude/output-styles/ploomes-design-system-*.claude/CLAUDE.md
Decision evidence
public snapshotAI called this Suspicious at 94.0% confidence as Dangerous Capability with medium false-positive risk.
Evidence for block
- package.json defines postinstall: node scripts/setup.mjs
- scripts/setup.mjs copies ai-extensions categories into consumer .claude/{skills,agents,commands,output-styles} during install
- scripts/setup.mjs removes prior prefixed .claude entries with rmSync before copying package content
- scripts/setup.mjs writes/updates consumer .claude/CLAUDE.md with an @import to package ai-extensions/CLAUDE.md
- ai-extensions contains Claude skills and instructions that become active agent control files
Evidence against
- No network endpoints or exfiltration code found in setup.mjs
- AI extension content inspected is product-aligned UI documentation/setup guidance
- No child_process, eval, native binary, or credential harvesting found in inspected sources
Behavioral surface
ChildProcessEnvironmentVarsFilesystem
HighEntropyStringsMinifiedUrlStrings
NoLicense
Source & flagged code
2 flagged · loading sourcepackage.jsonView file
•scripts.postinstall = node scripts/setup.mjs
High
Install Time Lifecycle Scripts
Package defines install-time lifecycle scripts.
package.jsonView on unpkgscripts/setup.mjsView file
1Install-time AI-agent control hijack evidence:
L9: * Mirrors each category from <src>/ flattened into the root of the consumer's
L10: * `.claude/<category>/`, prefixing each item with the lib name (skills are only
L11: * discovered at `.claude/skills/<skill>/SKILL.md` directly). The wipe removes
L12: * only the items carrying this prefix, leaving the project's own content intact.
L13: * If `<src>/CLAUDE.md` exists, injects a demarcated `@import` into the consumer's
L14: * `.claude/CLAUDE.md`.
L15: *
L16: * ai-extensions/skills/foo/SKILL.md -> .claude/skills/<PREFIX>-foo/SKILL.md
L17: *
...
L19: * During DS-monorepo dev the package lives in packages/ui (outside node_modules),
L20: * so the script is inert and the repo's `.claude/` stays intact.
L21: */
Payload evidence from ai-extensions/skills/setup-ploomes-ui/SKILL.md:
L1: ---
L2: name: setup-ploomes-ui
Critical
Ai Agent Control Hijack
Install-time source drops package-supplied AI-agent/MCP control files or instructions.
scripts/setup.mjsView on unpkg · L1Findings
1 Critical1 High2 Medium5 Low
CriticalAi Agent Control Hijackscripts/setup.mjs
HighInstall Time Lifecycle Scriptspackage.json
MediumEnvironment Vars
MediumStructural Risk Force Deep Review
LowScripts Present
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings
LowNo License