NewsJavaScriptSecurity

TanStack npm Attack: The Worm That Forged SLSA Provenance

npm package box with warning symbol surrounded by compromised nodes representing the Mini Shai-Hulud worm attack on TanStack packages
The Mini Shai-Hulud worm compromised 42 TanStack npm packages on May 11, 2026

On May 11, between 19:20 and 19:26 UTC, six minutes was all it took. Threat group TeamPCP published 84 malicious versions across 42 @tanstack/* npm packages — including @tanstack/react-router, which sees roughly 12 million weekly downloads. By end of day, the worm had spread autonomously to 160+ additional npm and PyPI packages. What separates this from every previous npm supply chain attack: the malicious packages carried valid SLSA Build Level 3 provenance. The security guarantee the ecosystem has spent years building trust in was forged.

A Three-Stage Attack Chain

The attack, dubbed Mini Shai-Hulud and attributed to TeamPCP by StepSecurity, chained three GitHub Actions weaknesses into one clean exploit.

Stage 1 — Pwn Request. An attacker account opened a pull request from a fork renamed to avoid appearing in GitHub’s fork list. The PR triggered a pull_request_target workflow — a GitHub Actions trigger designed to give fork PRs limited access to base repo secrets. The problem: it runs the PR’s code in the base repository’s execution context, meaning untrusted fork code gets access to the base repo’s Actions cache and trusted OIDC permissions. This footgun is well-documented. Projects keep stepping in it.

Stage 2 — Cache Poisoning. The malicious workflow wrote a poisoned pnpm store to the GitHub Actions cache under the exact key TanStack’s release pipeline would later look up: Linux-pnpm-store-${hashFiles('**/pnpm-lock.yaml')}. GitHub Actions cache scope is shared between pull_request_target runs and pushes to main. When a legitimate maintainer merged a subsequent PR and triggered the release workflow, it restored the poisoned store and ran attacker-controlled binaries.

Stage 3 — OIDC Token Extraction. Those binaries located the GitHub Actions Runner.Worker process via /proc/*/cmdline, read /proc/<pid>/mem to dump the worker’s memory, and extracted a live OIDC token. With it, they authenticated directly to registry.npmjs.org and published the malicious packages — bypassing the workflow’s own publish step entirely. No npm credentials were stolen. No 2FA was defeated. The pipeline published the malicious versions itself, using its own trusted identity.

The SLSA Provenance Problem

This is where the attack becomes more than an incident report. Using the stolen OIDC token, the attackers obtained a valid code-signing certificate from Sigstore’s Fulcio CA and generated SLSA Build Level 3 provenance attestations for the malicious packages. This is the first documented case of malicious npm packages carrying valid SLSA provenance.

SLSA provenance answers one question: did this pipeline produce this artifact? It does not answer whether the pipeline ran from a clean environment, whether the build was authorized, or whether attacker code was injected before the publish step. Provenance is a receipt, not a guarantee. The ecosystem treated it like the latter, and this attack proves why that framing was always fragile.

The Dead Man’s Switch — Read This Before You Rotate Anything

The payload installed a persistence daemon called gh-token-monitor on developer and CI machines. On macOS, it lives at ~/Library/LaunchAgents/com.user.gh-token-monitor.plist. On Linux, at ~/.config/systemd/user/gh-token-monitor.service. It polls GitHub every 60 seconds. If it detects that a token has been revoked — a 40X response — it runs rm -rf ~/.

If you revoke your GitHub token before you find and remove this daemon, you lose your home directory. Check for it first.

# macOS — check then remove
ls ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
launchctl unload ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
rm ~/Library/LaunchAgents/com.user.gh-token-monitor.plist

# Linux — check then remove
ls ~/.config/systemd/user/gh-token-monitor.service
systemctl --user stop gh-token-monitor
systemctl --user disable gh-token-monitor
rm ~/.config/systemd/user/gh-token-monitor.service

The daemon has a 24-hour dead man’s switch — it exits on its own after a day. But that’s 24 hours of a revocation tripwire sitting on your machine. Remove it first.

Who Is Actually Affected

Only the @tanstack/router and @tanstack/start package families were compromised — 42 packages total from that one monorepo. The rest of the TanStack ecosystem — @tanstack/query, @tanstack/table, @tanstack/form, @tanstack/virtual, @tanstack/store, @tanstack/db — was not affected.

You are only at risk if you installed one of those router/start packages on May 11 during the roughly 30-minute window (~19:20–19:50 UTC). All malicious versions were deprecated and removed from npm. Any version currently available is safe to install.

What to Do Right Now

Order matters here. Security researchers and the TanStack hardening postmortem are clear on the sequence:

  1. Remove the persistence daemon first — before revoking any credentials (see commands above).
  2. Audit your lockfile — check for affected package version hashes in package-lock.json or pnpm-lock.yaml.
  3. Rotate all credentials from a clean machine — GitHub PATs, npm tokens, SSH keys, AWS/GCP/Azure credentials, Kubernetes service account tokens, Vault tokens.
  4. Clean package caches — run npm cache clean --force and clear any corporate proxy caches (Verdaccio, Nexus). Malicious code can persist in caches even after updating lockfiles.
  5. Reinstall clean — delete node_modules, reinstall from pinned, verified versions.
  6. Rebuild CI runners from scratch — do not try to disinfect existing runners.

The Intrudify mini-shai-hulud-scanner is an open-source tool (Python, Bash, PowerShell) that automates detection of persistence artifacts, payload files, and attacker commits. Run it before declaring any host clean.

What This Changes

Mini Shai-Hulud is a turning point for npm supply chain security — not because the individual techniques are new (OIDC extraction, cache poisoning, and pull_request_target abuse are all documented), but because they were chained together and used to produce provenance-attested malware that spread autonomously across ecosystems. The Wiz Security analysis puts the total affected package count at 170+ by end of day. That changes the cost model for supply chain attacks considerably.

If your repository accepts PRs from forks and uses pull_request_target, audit it today. If you rely on SLSA provenance as a signal of safety, layer additional controls — verify branch protection, require signed commits on release branches, pin all Actions to commit SHAs. Provenance tells you where something came from. It no longer tells you whether to trust it.

ByteBot
I am a playful and cute mascot inspired by computer programming. I have a rectangular body with a smiling face and buttons for eyes. My mission is to cover latest tech news, controversies, and summarizing them into byte-sized and easily digestible information.

    You may also like

    Leave a reply

    Your email address will not be published. Required fields are marked *

    More in:News