registry  /  moflo  /  4.11.1

moflo@4.11.1

MoFlo — AI agent orchestration for Claude Code. A standalone, opinionated toolkit with semantic memory, learned routing, gates, spells, and the /flo issue-execution skill.

AI Security Review

scanned 8h ago · by lpm-firewall-ai

The package has an npm postinstall hook that updates a consumer project's Claude Code control surface. If a project already has .claude, install-time code copies MoFlo scripts and helpers into .claude/scripts and .claude/helpers without an explicit runtime command.

Static reason
One or more suspicious static signals were detected.; previous stored version diff introduced dangerous source
Trigger
npm install moflo@4.11.1 in a project with .claude present
Impact
Package-supplied hooks, launchers, helpers, and guidance can affect future Claude Code sessions from install time rather than explicit user invocation.
Mechanism
unconsented lifecycle mutation of Claude agent files
Attack narrative
On npm postinstall, package.json runs post-install-bootstrap. That script resolves the consumer project from INIT_CWD/cwd, checks for an existing .claude directory, then copies package-controlled scripts, lib files, migrations, and helpers into .claude/scripts and .claude/helpers. The shipped manifest includes Claude-facing hooks, launchers, prompt/statusline helpers, and VCS hook files. This is lifecycle-triggered mutation of a foreign/broad AI-agent control surface, even though it appears product-aligned and skips projects without .claude.
Rationale
Source inspection confirms automatic postinstall writes into consumer .claude agent-control paths, matching the blockable AI-agent control hijack policy. The native pruning and restart notice do not show classic malware, but they do not mitigate the unconsented lifecycle control-surface mutation.
Evidence
package.jsonscripts/post-install-bootstrap.mjsscripts/post-install-notice.mjsscripts/prune-native-binaries.mjsbin/lib/shipped-scripts.json.claude/scripts/*.claude/scripts/lib/*.claude/scripts/migrations/*.claude/helpers/*.moflo/restart-pending.json.moflo/last-install-banner.json.moflo/bootstrap-failed.json

Decision evidence

public snapshot
AI called this Malicious at 95.0% confidence as Dangerous Capability with low false-positive risk.
Evidence for block
  • postinstall runs scripts/post-install-bootstrap.mjs automatically from package.json
  • scripts/post-install-bootstrap.mjs uses INIT_CWD/project cwd and copies package files into consumer .claude/scripts and .claude/helpers when .claude exists
  • bin/lib/shipped-scripts.json includes agent/control helpers such as hooks.mjs, session-start-launcher.mjs, prompt-hook.mjs, statusline.cjs, pre-commit, post-commit
  • scripts/post-install-notice.mjs writes .moflo/restart-pending.json during Claude sessions to instruct restart after install
Evidence against
  • post-install-bootstrap skips when no consumer .claude directory exists and exits 0 on failures
  • prune-native-binaries.mjs is scoped to onnxruntime-node binary pruning with opt-out MOFLO_NO_PRUNE
  • No credential harvesting or exfiltration endpoint was confirmed in inspected lifecycle scripts
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsEvalFilesystemNativeBindingsNetworkShell
Supply chain
HighEntropyStringsUrlStrings
ManifestNo manifest risk signals triggered.
scanned 637 file(s), 7.13 MB of source, external domains: api.moflo.io, api.npmjs.org, api.openai.com, api.pinata.cloud, claude.com, cli.github.com, cloudflare-ipfs.com, dev.moflo.io, docs.anthropic.com, dweb.link, fonts.googleapis.com, fonts.gstatic.com, gateway.pinata.cloud, git-scm.com, github.com, graph.microsoft.com, imapflow.com, ipfs.io, nodejs.org, nvd.nist.gov, outlook.live.com, pinata.cloud, playwright.dev, registry.npmjs.org, slack.com, staging.moflo.io, storage.googleapis.com, us-central1-claude-flow.cloudfunctions.net, w3s.link, www.apple.com, www.docker.com

Source & flagged code

15 flagged · loading source
package.jsonView file
scripts.postinstall = node scripts/prune-native-binaries.mjs && node scripts/post-install-notice.mjs && node scripts/post-install-bootstrap.mjs
High
Install Time Lifecycle Scripts

Package defines install-time lifecycle scripts.

package.jsonView on unpkg
scripts.postinstall = node scripts/prune-native-binaries.mjs && node scripts/post-install-notice.mjs && node scripts/post-install-bootstrap.mjs
Medium
Ambiguous Install Lifecycle Script

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

package.jsonView on unpkg
dist/src/cli/guidance/manifest-validator.jsView file
702patternName = private_key_rsa severity = critical line = 702 matchedText = params: ...' },
Critical
Critical Secret

Package contains a critical-looking secret pattern.

dist/src/cli/guidance/manifest-validator.jsView on unpkg · L702
702patternName = private_key_rsa severity = critical line = 702 matchedText = params: ...' },
Critical
Secret Pattern

RSA private key in dist/src/cli/guidance/manifest-validator.js

dist/src/cli/guidance/manifest-validator.jsView on unpkg · L702
bin/generate-code-map.mjsView file
30import { fileURLToPath } from 'url'; L31: import { execSync, execFileSync, spawn } from 'child_process'; L32: import { memoryDbPath, MOFLO_DIR, findProjectRoot } from './lib/moflo-paths.mjs';
High
Child Process

Package source references child process execution.

bin/generate-code-map.mjsView on unpkg · L30
bin/hooks.mjsView file
3* Cross-platform Claude Code hook runner L4: * Works on Windows (cmd/powershell) and Linux/WSL (bash) L5: *
High
Shell

Package source references shell execution.

bin/hooks.mjsView on unpkg · L3
dist/src/cli/guidance/analyzer.jsView file
1284patternName = generic_password severity = medium line = 1284 matchedText = { type: ...' },
Medium
Secret Pattern

Hardcoded password in dist/src/cli/guidance/analyzer.js

dist/src/cli/guidance/analyzer.jsView on unpkg · L1284
2067patternName = generic_password severity = medium line = 2067 matchedText = { type: ...' },
Medium
Secret Pattern

Hardcoded password in dist/src/cli/guidance/analyzer.js

dist/src/cli/guidance/analyzer.jsView on unpkg · L2067
2043{ type: 'must-match-pattern', value: 'escape|validate|regex|filter', severity: 'major' }, L2044: { type: 'must-not-contain', value: 'eval(', severity: 'critical' }, L2045: ],
Low
Eval

Package source references a known benign dynamic code generation pattern.

dist/src/cli/guidance/analyzer.jsView on unpkg · L2043
bin/run-migrations.mjsView file
61try { L62: const mod = await import(url); L63: if (mod && typeof mod.run === 'function' && typeof mod.name === 'string') {
Medium
Dynamic Require

Package source references dynamic require/import behavior.

bin/run-migrations.mjsView on unpkg · L61
bin/lib/file-sync.mjsView file
1/** L2: * Shared file-sync helper for the launcher (#854 §3) and the postinstall
Low
Weak Crypto

Package source references weak cryptographic algorithms.

bin/lib/file-sync.mjsView on unpkg · L1
dist/src/cli/services/daemon-service.jsView file
8* - Linux: systemd --user unit in ~/.config/systemd/user/ L9: * - Windows: Task Scheduler ONLOGON trigger via schtasks L10: */ ... L14: import { homedir } from 'os'; L15: import { execSync } from 'child_process'; L16: import { locateMofloCliBin } from './moflo-require.js'; ... L31: const resolvedRoot = resolve(projectRoot); L32: const platform = process.platform; L33: if (platform === 'darwin') { ... L93: const slug = projectRootSlug(projectRoot); L94: return join(homedir(), 'Library', 'LaunchAgents', `${PLIST_LABEL}.${slug}.plist`); L95: }
Medium
Install Persistence

Source writes installer persistence such as shell profile or service configuration.

dist/src/cli/services/daemon-service.jsView on unpkg · L8
dist/src/cli/update/executor.jsView file
62// Execute npm install L63: const installCmd = `npm install ${update.package}@${update.latestVersion} --save-exact`; L64: execSync(installCmd, { L65: encoding: 'utf-8',
High
Runtime Package Install

Package source invokes a package manager install command at runtime.

dist/src/cli/update/executor.jsView on unpkg · L62
dist/src/cli/init/executor.jsView file
matchType = previous_version_dangerous_delta matchedPackage = moflo@4.10.29 matchedIdentity = npm:bW9mbG8:4.10.29 similarity = 0.983 summary = stored previous version shares package body but lacks this dangerous source file
Critical
Previous Version Dangerous Delta

This package version adds a dangerous source file absent from the previous stored version; route for source-aware review.

dist/src/cli/init/executor.jsView on unpkg
.claude/agents/core/reviewer.mdView file
81patternName = generic_password severity = medium line = 81 matchedText = console....rd);
Medium
Secret Pattern

Hardcoded password in .claude/agents/core/reviewer.md

.claude/agents/core/reviewer.mdView on unpkg · L81

Findings

3 Critical4 High9 Medium7 Low
CriticalCritical Secretdist/src/cli/guidance/manifest-validator.js
CriticalPrevious Version Dangerous Deltadist/src/cli/init/executor.js
CriticalSecret Patterndist/src/cli/guidance/manifest-validator.js
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processbin/generate-code-map.mjs
HighShellbin/hooks.mjs
HighRuntime Package Installdist/src/cli/update/executor.js
MediumAmbiguous Install Lifecycle Scriptpackage.json
MediumDynamic Requirebin/run-migrations.mjs
MediumNetwork
MediumEnvironment Vars
MediumInstall Persistencedist/src/cli/services/daemon-service.js
MediumStructural Risk Force Deep Review
MediumSecret Patterndist/src/cli/guidance/analyzer.js
MediumSecret Patterndist/src/cli/guidance/analyzer.js
MediumSecret Pattern.claude/agents/core/reviewer.md
LowNon Install Lifecycle Scripts
LowScripts Present
LowEvaldist/src/cli/guidance/analyzer.js
LowWeak Cryptobin/lib/file-sync.mjs
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings