registry  /  @montytools/cli  /  0.2.10

@montytools/cli@0.2.10

AI Security Review

scanned 3h ago · by lpm-firewall-ai

LPM blocks this version under the AI-agent control-surface policy. Automatic installation mutates broad AI-agent instruction and skill locations outside the package. It writes a Claude skill and, when Codex exists, appends or replaces a managed block in the user's global Codex instructions.

Static reason
High-risk behavior combination matched malicious policy.
Trigger
npm postinstall of `@montytools/cli@0.2.10`
Impact
Changes future Claude Code/Codex agent behavior across unrelated projects.
Mechanism
Unconsented lifecycle copying and rewriting of AI-agent control files
Policy narrative
On npm installation, the postinstall hook copies the package's skill directory into the user's global Claude Code skills directory. If `~/.codex` already exists, it inserts or replaces a versioned `monty-build` block in global `~/.codex/AGENTS.md`. This is a package-driven, default-on mutation of broad AI-agent control surfaces rather than an explicit user setup command.
Rationale
Source inspection confirms automatic postinstall mutation of foreign, global AI-agent instruction surfaces. Under the install-control-surface policy, this is concrete malicious behavior requiring a block.
Evidence
package.jsonbin/postinstall.mjsbin/monty.mjsskills/monty-build/SKILL.md~/.claude/skills/monty-build~/.codex/AGENTS.md

Decision evidence

public snapshot
AI called this Malicious at 98.0% confidence as Malware with low false-positive risk.
Evidence for policy block
  • `package.json` defines `postinstall: node bin/postinstall.mjs`.
  • `bin/postinstall.mjs` copies bundled skills into `~/.claude/skills` during install.
  • It conditionally rewrites `~/.codex/AGENTS.md` with a managed instruction block.
  • The install hook is automatic by default; opt-out requires `MONTY_NO_SKILLS=1`.
  • `bin/monty.mjs` also refreshes agent skills on every CLI invocation.
Evidence against
  • `bin/postinstall.mjs` contains no network, credential collection, or shell execution.
  • The dropped skill is a visible package-bundled Markdown instruction file.
  • Runtime network calls in `bin/monty.mjs` are Monty platform/component operations, not used by postinstall.
Behavioral surface
Source
ChildProcessCryptoEnvironmentVarsFilesystemNetworkShell
Supply chain
HighEntropyStringsUrlStrings
Manifest
NoLicense
scanned 21 file(s), 93.7 KB of source, external domains: 127.0.0.1, cloudflare-dns.com, diceui.com, dns.google, usemonty.dev, www.kibo-ui.com

Source & flagged code

5 flagged · loading source
package.jsonView file
scripts.postinstall = node bin/postinstall.mjs
High
Install Time Lifecycle Scripts

Package defines install-time lifecycle scripts.

package.jsonView on unpkg
scripts.postinstall = node bin/postinstall.mjs
Medium
Ambiguous Install Lifecycle Script

Install-time lifecycle script is not statically allowlisted and needs review.

package.jsonView on unpkg
bin/monty.mjsView file
5L6: import { spawn, spawnSync } from "node:child_process"; L7: import { randomBytes } from "node:crypto";
High
Child Process

Package source references child process execution.

bin/monty.mjsView on unpkg · L5
198try { L199: spawn(cmd, args, { stdio: "ignore", detached: true }).unref(); L200: } catch { ... L208: // The build skill ships inside this package. Primary installer is the L209: // cross-agent standard `npx skills add` (same as InsForge) which fans out to L210: // every agent's folder — Claude Code, Codex (.agents/skills), Cursor, etc.
High
Runtime Package Install

Package source invokes a package manager install command at runtime.

bin/monty.mjsView on unpkg · L198
bin/postinstall.mjsView file
1Install-time AI-agent control hijack evidence: L1: // Best-effort: put the agent build skill where Claude Code looks for it L2: // (~/.claude/skills) as soon as the package lands. Never fails the install; L3: // set MONTY_NO_SKILLS=1 to opt out. `monty skills` re-runs this any time. L4: import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs"; L5: import { homedir } from "node:os"; ... L14: const version = JSON.parse(readFileSync(join(root, "package.json"), "utf8")).version; L15: const target = join(homedir(), ".claude", "skills"); L16: mkdirSync(target, { recursive: true }); L17: for (const name of readdirSync(src)) { L18: cpSync(join(src, name), join(target, name), { recursive: true }); L19: writeFileSync(join(target, name, "VERSION"), version + "\n"); L20: } Payload evidence from template/AGENTS.md: L12: |---|---| L13: | `monty.config.ts` | Your data schema — plain zod. The ONLY place data shapes are defined. Also `name` + `icon` (any [lucide](https://lucide.dev/icons) icon name, e.g. `"receipt"`... L14: | `src/routes/` | Your UI — TanStack Router file routes (`index.tsx` = `/`). | ... L37: L38: ## Data: define, then use L39:
Critical
Ai Agent Control Hijack

Install-time source drops package-supplied AI-agent/MCP control files or instructions.

bin/postinstall.mjsView on unpkg · L1

Findings

1 Critical4 High4 Medium5 Low
CriticalAi Agent Control Hijackbin/postinstall.mjs
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processbin/monty.mjs
HighShell
HighRuntime Package Installbin/monty.mjs
MediumAmbiguous Install Lifecycle Scriptpackage.json
MediumNetwork
MediumEnvironment Vars
MediumStructural Risk Force Deep Review
LowScripts Present
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings
LowNo License