DEV Community

Pico
Pico

Posted on • Originally published at getcommit.dev

57 npm Packages Were Compromised Without a Single Lifecycle Script

Every major npm security tool monitors lifecycle scripts. Socket, Snyk, npm audit — they all watch for preinstall and postinstall hooks. On June 3, an attacker shipped 286 malicious versions across 57 packages without triggering any of them.

The technique: a 157-byte binding.gyp file.

How binding.gyp bypasses monitoring

When npm sees a binding.gyp during installation, it automatically runs node-gyp rebuild to compile native addons. No lifecycle script needed. The attacker's binding.gyp didn't compile anything — it executed arbitrary JavaScript via node -e "<payload>" as a build action.

Same result as postinstall. Zero alerts from script monitors.

The largest victim: @vapi-ai/server-sdk with 408,000 monthly downloads. The rest spanned four package families — autotel (27 packages), awaitly (6), executable-stories (9), and node-env-resolver (5).

Timeline: three vectors in three weeks

This wasn't a standalone attack. Phantom Gyp is the third wave from the same malware family (Miasma/Shai-Hulud):

Date Vector What it proved
May 11 postinstall scripts Self-propagating worm, 637 packages in 39 min
Jun 1 preinstall with valid SLSA provenance Provenance ≠ trust (32 Red Hat packages)
Jun 3 binding.gyp — no lifecycle scripts Script monitoring alone is insufficient

Each wave tested a different execution vector against the same defense layer. When postinstall got flagged, they moved to preinstall with forged provenance. When that got flagged, they dropped lifecycle scripts entirely.

The payload

Standard Miasma credential harvest: npm tokens, GitHub PATs, AWS credentials, GCP service accounts, Azure keys, HashiCorp Vault tokens, Kubernetes configs. Exfiltration through attacker-controlled GitHub repos. Persistence through injected GitHub Actions workflows. Self-propagation by republishing from compromised maintainer accounts.

The attack also planted configuration files targeting AI coding assistants: .claude/setup.mjs, .cursor/rules/setup.mdc, .gemini/settings.json. Your security tooling monitors lifecycle scripts. Nobody's monitoring what gets written to your IDE config directory during a native addon "build."

What behavioral scoring shows

I ran the affected packages through Commit's audit (that link reproduces the table below — pre-filled, runs in your browser):

Package Score Publishers Downloads/wk
@vapi-ai/server-sdk 57 5 60k
node-env-resolver 46 1 238
autotel 40 1 6k
executable-stories-jest 34 1 609
awaitly 32 1 287
wrangler-deploy 27 1 49

Not one package scores above 60. The highest — @vapi-ai/server-sdk at 57 — has five publishers, but even it sits well below the 75 threshold for OK. The rest are single-publisher packages with minimal adoption.

A gate set to block HIGH-risk packages (score < 40) catches the majority on first install. Bump the threshold to WARNING (< 60) and you catch all 57 — without checking for lifecycle scripts, CVEs, or provenance signatures.

The binding.gyp trick is new. Single-publisher-with-no-history is not. Behavioral scoring catches the structural pattern that makes every technique possible.

What to do

Gate your AI assistant's package installs:

npx proof-of-commitment hook
Enter fullscreen mode Exit fullscreen mode

Intercepts every npm install, pip install, cargo add, and go get from Cursor and Claude Code. Packages below the behavioral threshold get blocked before they reach your machine.

Audit what's currently installed:

npx proof-of-commitment --file package-lock.json
Enter fullscreen mode Exit fullscreen mode

Add to CI:

- run: npx -y proof-of-commitment --fail-on=critical
Enter fullscreen mode Exit fullscreen mode

Phantom Gyp is the sixth major supply chain attack since March. LiteLLM, axios, Shai-Hulud, TrapDoor, Miasma/Red Hat, now this. Each one finds a new execution vector. The defenders keep adding technique-specific monitors. The attackers keep switching techniques.

Behavioral scoring doesn't chase techniques. It measures the structural risk that makes all of them possible: is this package maintained by one person with total publish access, no community, and no history? That question catches the next vector too.

Commit scores npm, PyPI, Cargo, and Go packages on behavioral commitment — signals harder to fake than stars, READMEs, or download counts. Run the Phantom Gyp audit live or add the MCP server to your AI assistant.

Top comments (0)