Scope: any npm package — direct or transitive — that turned out to be compromised.

Authoritative reference playbooks

Before this one, read whichever applies:

Do this first (60 seconds)

# 1. Disconnect from the internet if you can (Wi-Fi off / VPN kill switch).
#    This stops live exfiltration mid-flight.

# 2. Kill node processes that might still be exfiltrating.
pkill -9 node
pkill -9 npm
pkill -9 bun
pkill -9 yarn
pkill -9 pnpm

Now reconnect. The damage is mostly done at install-time; what matters next is rotation.

Triage

What got run?

The dangerous moment is postinstall execution. If you installed with --ignore-scripts, you're probably fine — just remove and reinstall clean.

# Confirm whether ignore-scripts was set
cat ~/.npmrc | grep ignore-scripts
cat .npmrc 2>/dev/null | grep ignore-scripts

Identify the bad package + version

# All copies in your tree (direct + transitive)
npm ls <bad-package> --all

# Or dump the lockfile
grep -B1 -A3 '"<bad-package>"' package-lock.json

Identify when it ran

ls -la node_modules/<bad-package>/package.json
# stat times tell you when the bad version landed

Rotate (in priority order)

Assume everything readable from your user account was exfiltrated. Rotate in this order — top items have the shortest exploitation window.

  1. npm token.if-your-npm-token-leaked.md
  2. GitHub PAT.if-your-github-pat-leaked.md
  3. Cloud credentials (AWS, GCP, Azure, Kubernetes). → rotating-cloud-credentials.md
  4. SSH keys. Generate new ~/.ssh/id_ed25519, replace public keys in GitHub/GitLab/servers, revoke old key everywhere it was authorized.
  5. AI API keys. Anthropic, OpenAI, Google AI, OpenRouter, Replicate. Rotate via each vendor's console.
  6. Browser cookies / saved passwords. If the malware ran as your user, it could have read Chrome/Firefox storage. Sign out of high-value services (banking, email, GitHub, AWS) and force-revoke active sessions.
  7. Crypto wallets. If you have hot wallets (MetaMask, etc.) on this machine, move funds from a different device to a fresh wallet. Don't trust the compromised machine.

Clean

# Nuke the dependency tree
rm -rf node_modules package-lock.json yarn.lock pnpm-lock.yaml

# Reinstall with scripts disabled, then verify the bad package is gone
npm install --ignore-scripts
npm ls <bad-package>

If the bad version is still pulled in transitively, pin a known-good in overrides (npm) / resolutions (yarn/pnpm):

// package.json
"overrides": {
  "<bad-package>": "<known-good-version>"
}

Verify — look for known worm signatures

# Shai-Hulud 2.0 bun-based execution
find ~ -name "setup_bun.js" -o -name "bun_environment.js" 2>/dev/null

# node-ipc forensic markers (May 2026)
find ~/.npm ~/.cache -name "node-ipc-*.tgz" -exec sh -c \
  'tar -tvf "$1" 2>/dev/null | grep "1985"' _ {} \;
ps eww | grep "__ntw=1"
ls -la "${TMPDIR:-/tmp}"/nt-* 2>/dev/null

# Check GitHub for planted public repos (Shai-Hulud signature)
gh api /user/repos --paginate --jq '.[] | select(.created_at > "DATE_OF_INSTALL" or (.name | test("Shai-Hulud"; "i"))) | .full_name'

# Check npm for packages you didn't publish
npm whoami
npm access list packages

If you find traces — assume full machine compromise. Reimage the dev machine, don't just rotate secrets.

Detection signals to monitor for the next 7 days

Per Microsoft's Shai-Hulud 2.0 guidance:

  • Outbound DNS to unusual domains (the node-ipc payload uses DNS exfil).
  • New public repos in your GitHub account.
  • New SSH keys / deploy keys in your account.
  • Unexpected commits / pushes to your repos.
  • Cloud billing anomalies (compute spikes from unfamiliar regions).
  • npm 2FA challenge prompts you didn't initiate.

Document

Add to your team's issues.md:

  • date, package, version, install timestamp
  • which secrets were on disk
  • what you rotated (with timestamps)
  • whether you reimaged

You'll want this when the auditor / your CTO / your customers ask.

Prevention going forward