57 Packages Compromised Without a Single Lifecycle Script

The Phantom Gyp technique ships a weaponized binding.gyp that triggers code execution during npm install. No preinstall hook, no postinstall hook. It bypasses every lifecycle script monitor on the market.

Two days after the Red Hat Miasma attack compromised 32 packages using provenance-valid lifecycle scripts, the same malware family pivoted. This time it didn't use lifecycle scripts at all.

On June 3 at 23:30 UTC, a compromised maintainer account published malicious versions of @vapi-ai/server-sdk — the official Vapi voice AI SDK, 408,000 monthly downloads. Over the next hour, 56 more packages fell across the autotel, awaitly, executable-stories, and node-env-resolver families. 286 malicious versions total.

StepSecurity named the technique "Phantom Gyp." Snyk tracks the full incident.

The technique

Every major security tool monitors lifecycle scripts: preinstall, postinstall, install. Socket flags them. Snyk scans them. npm warns about them. The Red Hat Miasma wave two days earlier used preinstall and got caught within hours.

Phantom Gyp doesn't use any of them.

Instead, it ships a 157-byte binding.gyp file. When npm install detects a binding.gyp, it automatically invokes node-gyp rebuild to compile native addons. The attacker's binding.gyp calls node -e "<payload>" as a "build action" — executing arbitrary JavaScript during install without triggering a single lifecycle script alert.

This is a 14-year-old npm behavior. It's documented. It's how native modules build. And until last week, nobody used it as an attack vector.

The payloads

Same Miasma/Shai-Hulud malware family. The payload harvested npm, GitHub, AWS, GCP, Azure, HashiCorp Vault, and Kubernetes credentials. It exfiltrated through attacker-controlled GitHub repos. It injected GitHub Actions workflows for persistence. And it self-propagated by republishing packages from every maintainer account it could reach.

The largest victim, @vapi-ai/server-sdk, is the primary way developers integrate Vapi's voice AI platform. A compromised version in a CI pipeline could propagate through every downstream project that depends on it.

What behavioral signals show

I scored the compromised packages with Commit:

PackageScorePublishersWeekly DLAgeProvenance
@vapi-ai/server-sdk475100K1.1y
ai-sdk-ollama49142K0.8y
autotel4016K1.2y
awaitly3212870.5y
node-env-resolver281920.4y

Every package except @vapi-ai/server-sdk has a single npm publisher. Three are under a year old. The attack surface is the same one Commit flags by design: single-publisher packages with limited oversight.

The Red Hat packages two days earlier scored 65–83 — high enough that static scoring alone wouldn't have flagged them. These score 28–49. Behavioral signals would have.

What this changes

Lifecycle script monitoring is necessary but no longer sufficient. binding.gyp opens a second execution path that most security tools don't scan. And it's been there since 2012.

The Miasma lineage has now used three distinct execution vectors in three weeks:

  • TanStack (May 11): postinstall lifecycle script
  • Red Hat (June 1): preinstall lifecycle script with valid SLSA provenance
  • Phantom Gyp (June 3): binding.gyp native addon hook — no lifecycle script at all

Each iteration bypasses the defense that caught the last one. The constant across all three: compromised single-point-of-failure accounts.

Check your project

npx proof-of-commitment

Scores every dependency in your lockfile. Packages compromised in the Phantom Gyp attack are flagged in results. If you depend on @vapi-ai/server-sdk, ai-sdk-ollama, or any autotel/awaitly/executable-stories package — verify you're on a clean version.