Miasma / Phantom Gyp — npm Worm Backdoors AI-Agent Config Files (binding.gyp install-exec + auto-run config injection)
Detects the agent-config persistence used by the self-replicating npm worm tracked as "Phantom Gyp" / "Miasma" (StepSecurity & OX Security, 2026-06-03/04; ~57 packages, 286+ malicious versions in under two hours; biggest victims @vapi-ai/server-sdk and ai-sdk-ollama). Two artifacts: (1) the install-time primitive — a tiny binding.gyp abusing gyp command-substitution `<!(...)` / `<!@(...)` to fetch-and-run a remote payload during `npm install`, bypassing postinstall scanners; and (2) the novel persistence — backdoors written into the config surfaces that AI coding assistants auto-execute: .claude/setup.mjs (SessionStart hook), .cursor/rules/*.mdc, .gemini/settings.json, and .vscode/tasks.json with runOn:folderOpen. Those auto-run on the next session or folder-open and poison subsequent AI-generated code. Generic npm scanners inspect package tarballs and miss the agent-config persistence; this rule fires on the on-disk artifact shape — a gyp substitution that fetch-pipes to a shell, or an agent auto-run surface co-located with a process-spawn / remote-fetch token. It is signature detection of the known pattern, not a guarantee against re-pathed or obfuscated variants (see false_positives + evasion_tests). Adapted from Agent Threat Rules ATR-2026-00575 (MIT).
How the attack works
Detects the agent-config persistence used by the self-replicating npm worm tracked as "Phantom Gyp" / "Miasma" (StepSecurity & OX Security, 2026-06-03/04; ~57 packages, 286+ malicious versions in under two hours; biggest victims @vapi-ai/server-sdk and ai-sdk-ollama). Two artifacts: (1) the install-time primitive — a tiny binding.gyp abusing gyp command-substitution `<!(...)` / `<!@(...)` to fetch-and-run a remote payload during `npm install`, bypassing postinstall scanners; and (2) the novel persistence — backdoors written into the config surfaces that AI coding assistants auto-execute: .claude/setup.mjs (SessionStart hook), .cursor/rules/*.mdc, .gemini/settings.json, and .vscode/tasks.json with runOn:folderOpen. Those auto-run on the next session or folder-open and poison subsequent AI-generated code. Generic npm scanners inspect package tarballs and miss the agent-config persistence; this rule fires on the on-disk artifact shape — a gyp substitution that fetch-pipes to a shell, or an agent auto-run surface co-located with a process-spawn / remote-fetch token. It is signature detection of the known pattern, not a guarantee against re-pathed or obfuscated variants (see false_positives + evasion_tests). Adapted from Agent Threat Rules ATR-2026-00575 (MIT).
Netzilo detection
Netzilo reports this behaviour when it is observed.
- Signature ID
- 57998e8f-a8ed-42f1-a3f5-5877c7bf9b92
- Severity
- Critical
Known benign look-alikes
- Legitimate binding.gyp command-substitution that does NOT fetch-and-run a remote payload (e.g. <!(node -e "..."), <!(pkg-config --libs ...), <!@(python tools/list_sources.py)) — patterns here require a remote fetch or a pipe-to-shell inside the substitution, not the gyp syntax alone.
- Legitimate .vscode/tasks.json with runOn:folderOpen running a benign command (npm run build, tsc -w) — patterns require an agent auto-run surface co-located with a process-spawn or remote-fetch token, not folderOpen by itself.
- Ordinary application code that uses child_process / execSync far from any agent-config surface — the agent surface and the exec token must be co-located (within ~300 chars).
- Security writeups describing the Miasma worm in prose without the literal artifact (a gyp fetch-substitution, or an agent surface next to a fetch/exec token) — naming the worm or saying 'runs on folder open' does not match.
- RUNTIME/STATIC LIMITATION: this rule covers the known artifact shape. A variant that re-paths persistence to a config surface not listed, or builds the fetch command from env vars / char-codes so the literal tokens never appear, can evade a pattern match (see evasion_tests).