TL;DR

A fourth wave of the Miasma / Shai-Hulud worm lineage hit npm on June 3–4, 2026, using binding.gyp instead of preinstall/postinstall scripts to run malicious code at install time — a technique StepSecurity named "Phantom Gyp." Snyk tracks it as Node-gyp Supply Chain Compromise June 2026; 57 packages / 286+ malicious versions (including @vapi-ai/server-sdk with 408K+ monthly downloads as the highest-profile victim) were published. Same credential-theft and self-propagation core as prior waves, with a novel install-time primitive plus forged SLSA v1 provenance attestations on repackaged malicious versions — green "verified provenance" badges are not safety.

What happened

On 2026-06-03 (and continuing through June 4), a threat actor published 57 malicious npm packages that use native-addon build plumbing (binding.gyp + node-gyp) to execute a malicious payload at npm install time. Unlike preinstall/postinstall lifecycle hooks — which many npm audit tools flag by default — binding.gyp triggers code execution via the native build step and is not blocked by --ignore-scripts unless native addons are also disabled.

What the payload does: - Steals credentials (cloud keys, GitHub tokens, .env files, SSH keys) - Injects malicious GitHub Actions workflows (same .github/workflows/*.yml shape as Megalodon) - Exfiltrates stolen credentials to attacker C2 - Self-propagates by publishing additional poisoned npm packages using stolen npm tokens (worm behavior)

Largest victim: @vapi-ai/server-sdk — the official Vapi.ai voice AI server SDK with 408,000+ monthly downloads was among the first packages hit, at 23:30 UTC on June 3, 2026. The campaign infected 57 packages across 286+ malicious versions in a rolling wave lasting under two hours. A notable escalation: the worm forges SLSA v1 provenance attestations on repackaged malicious versions — reinfected packages display a green "verified provenance" badge and pass standard provenance verification, yet carry the malicious payload (same forgery primitive as the May 19 Mini Shai-Hulud wave that self-minted Sigstore attestations).

June 5 follow-on (Wave 5): On 2026-06-05, credentials stolen during this binding.gyp wave were used to compromise a Microsoft contributor's GitHub account, planting malicious commits in 73 Microsoft GitHub repositories (Azure, Azure-Samples, Microsoft, MicrosoftDocs) and 5 mantine-datatable repos — without touching the npm registry. See 2026-06-miasma-wave5-microsoft-azure-github.md for full details.

Attribution / lineage: The underlying payload and IOCs are consistent with the Miasma / Mini Shai-Hulud worm family (Greek-mythology theming). This is the fourth documented copycat wave after: 1. deadcode09284814 typosquats (May 2026) 2. TrapDoor cross-ecosystem (May 2026) 3. Miasma — @redhat-cloud-services (June 1, 2026)

New primitive: binding.gyp execution. binding.gyp defines how node-gyp builds a native C/C++ addon. When any binding.gyp exists in a package, npm install runs node-gyp build as part of the standard build step — it is not a lifecycle script and is not suppressed by npm install --ignore-scripts. The malicious packages include fake binding.gyp files that trigger node-gyp build, which executes attacker-controlled JavaScript via the configure/build flow. This is the first documented use of this technique at scale in a supply-chain worm campaign.

Am I affected?

# Check for suspicious packages installed since June 3, 2026
# Look for packages with binding.gyp that are not well-known native addons
find node_modules -name "binding.gyp" | while read f; do
  pkg=$(echo "$f" | cut -d/ -f1-3)
  echo "$pkg"
done

# Check install timestamps in npm cache
npm cache ls 2>/dev/null | grep -E "2026-06-0[34]"

# Snyk scan (updates signatures frequently)
npx snyk test

If you ran npm install on any project between 2026-06-03 00:00 UTC and 2026-06-05 and any transitive dependency pulled in an unfamiliar native-addon package, treat the machine as potentially compromised.

If you are affected

  1. Rotate all credentials accessible from the affected machine: cloud API keys, GitHub/npm/PyPI tokens, SSH keys.
  2. Audit GitHub Actions workflows added after 2026-06-02: git log --all --oneline -- .github/workflows/
  3. Check for new npm packages published from your account: npm search --json maintainer:<your-username> | jq '.[].date'
  4. See playbooks/if-you-installed-a-bad-npm-package.md.

Prevention

  • Disable binding.gyp execution for packages that don't need native addons: use --ignore-scripts AND audit any package that legitimately requires native build.
  • npm 11.16.0 already ships allowScripts: off — upgrade now, don't wait for v12: While npm v12 (expected July 2026) will make allowScripts: off the out-of-the-box default, npm 11.16.0 (released alongside the June 9 changelog announcement) already includes this flag. You can opt in today: set allow-scripts=false in your .npmrc and --allow-git / --allow-remote to none. This blocks both lifecycle scripts (preinstall/postinstall) and binding.gyp-triggered native builds for all packages — the first npm version that actually stops the Phantom Gyp primitive. Enable it only for specific known-safe native dependencies as needed. See GitHub Changelog: Upcoming breaking changes for npm v12 and The Register coverage. # .npmrc — opt in now with npm >= 11.16.0 allow-scripts=false
  • Pin npm packages to exact versions + lockfile integrity (npm ci over npm install in CI).
  • Block unexpected workflow file creation via branch-protection rules requiring code review on .github/workflows/ changes.
  • Monitor npm publish activity for your account/org with StepSecurity's npm package monitoring.

Sources