The TanStack Supply-Chain Attack Is a Masterclass in How NPM Compromises Actually Work

Attackers didn't steal a password — they hijacked the build pipeline itself, and your 'trusted packages' defence was never going to catch it.

TokenDance Editors·12 May 2026
The TanStack Supply-Chain Attack Is a Masterclass in How NPM Compromises Actually Work

Six Minutes. 84 Malicious Packages. Zero Stolen Passwords.

Think about how a food-delivery app works: you don't cook the meal yourself, you trust the restaurant, the rider, and the platform to deliver something safe. Now imagine the attacker didn't poison the food — they put on a legitimate rider uniform, used a real delivery bag, and got waved through every checkpoint. That's roughly what happened to TanStack on May 11, 2026. Between 19:20 and 19:26 UTC — six minutes — 84 malicious npm package artifacts were published across 42 packages in the @tanstack namespace. No TanStack maintainer's password was stolen. No credentials were phished. The packages were published by TanStack's own legitimate release pipeline, using its own trusted identity. The attacker didn't break the lock; they walked in through the front door wearing a staff badge. @tanstack/react-router alone receives over 12.7 million weekly downloads. Across all its packages, TanStack sees around 56 million weekly downloads. Within hours of those six minutes, the malicious versions had spread to Mistral AI, UiPath, and dozens of other maintainers. The attack is attributed by StepSecurity to a threat group called TeamPCP, and it carries a CVE severity rating of Critical (CVE-2026-45321).

Six Minutes. 84 Malicious Packages. Zero Stolen Passwords.

The Attack Chain: Three Vulnerabilities, All Hiding in Plain Sight

TanStack founder Tanner Linsley published an unusually candid postmortem. The attack chained three GitHub Actions abuse techniques together — none of them zero-days, all of them documented weaknesses. **Step 1 — The Pwn Request.** The attacker forked TanStack/router at 17:16 on May 10 and authored a malicious commit. They then opened a pull request against the main TanStack repository using the `pull_request_target` workflow trigger — a known pattern called a "Pwn Request" — which causes scripts to auto-run with elevated repository privileges even when the code comes from an external fork. **Step 2 — Cache Poisoning.** That initial run poisoned the GitHub Actions cache across the fork-to-base trust boundary. Linsley described this as a variant of a known GitHub Actions vulnerability discovered in 2024. The poisoned cache meant subsequent legitimate workflow runs would load attacker-controlled code. **Step 3 — OIDC Token Extraction.** With code running inside the legitimate pipeline, the malware extracted the npm OIDC token directly from the Actions runner process memory. OIDC (OpenID Connect) tokens are the modern replacement for stored npm passwords — they're meant to be more secure because they're short-lived and tied to a specific pipeline run. The attacker didn't steal a stored secret; they read the token out of live memory while the pipeline was using it.

The Attack Chain: Three Vulnerabilities, All Hiding in Plain Sight

Why Your 'We Use Trusted Packages' Defence Didn't Work — And Couldn't

Here's the part that should make any engineering team pause. The malicious packages carried valid SLSA Build Level 3 provenance attestations — cryptographic certificates generated by Sigstore that are specifically designed to prove a package was built from a trusted source. This is the first documented npm worm to achieve this. Sigstore verified the build process correctly, because the build process *was* the legitimate TanStack pipeline. What SLSA provenance guarantees is that a specific pipeline produced a specific artifact. What it does not — and cannot — guarantee is that the code fed into that pipeline was safe. Every compromised package version contained a newly injected `router_init.js` file, approximately 2.3 MB in size, with aggressive obfuscation including hex-encoded identifier lookups and control-flow flattening. The payload reads files from over 100 hardcoded paths — cloud credentials, SSH keys, GitHub tokens, npm tokens, Kubernetes service account tokens, crypto wallets, VPN configurations, shell history, and messaging app credentials. There is also a dead-man's switch. The malware installs a persistence hook that polls GitHub's API every 60 seconds with the stolen token. If that token is revoked — meaning the victim has detected the breach and is trying to respond — the service runs a command to wipe the local disk completely. As one developer warned on GitHub: "Please be careful when revoking tokens." Rotating credentials too quickly without first isolating the environment triggers the wipe.

Why Your 'We Use Trusted Packages' Defence Didn't Work — And Couldn't

This Is Wave Four. The Worm Has Been Learning.

The TanStack attack doesn't exist in isolation. It's the fourth documented wave of the Shai-Hulud worm toolchain, and each wave has been technically more sophisticated than the last. The first wave (September 2025) compromised 500+ packages across 700+ repos and introduced the self-propagating npm worm concept. Wave two (November 2025) scaled to 492 packages with 132 million monthly downloads and 25,000+ repos, added a `preinstall` hook so the malware runs without any human interaction beyond `npm install`, and introduced a home-directory destruction fallback. Wave three (April 2026) hit SAP and Intercom ecosystems and introduced AI coding agent persistence — specifically targeting `.claude/settings.json` — plus encrypted exfiltration. Wave four, the TanStack attack, achieved something no prior supply chain attack had demonstrated: publishing malicious packages that are cryptographically indistinguishable from legitimate ones by provenance attestation. The worm is also now a true self-propagating threat: after stealing credentials from one CI/CD pipeline, it enumerates every package that maintainer controls and publishes infected versions of each. That's how the infection spread from TanStack to UiPath, DraftLab, Mistral AI, OpenSearch, Guardrails AI, and Squawk — not through separate attacks, but through the worm using TanStack's stolen credentials to compromise its neighbours.

This Is Wave Four. The Worm Has Been Learning.

What Actually Would Have Stopped This — Specific Controls, Not a Checklist

Generic advice like "audit your dependencies" would not have blocked this attack. Here's what the postmortem and security researchers identify as the specific controls that matter. **Pin workflow permissions tightly.** The `pull_request_target` trigger is the root of the Pwn Request pattern. Workflows that handle pull requests from forks should never run with write permissions or access to secrets. This is a configuration choice, not a product purchase. **Enforce network egress allowlists in CI.** StepSecurity's Harden-Runner tool detects anomalous outbound network traffic from GitHub Actions runners. The C2 domain used by the malware was added to StepSecurity's global block list after detection. An egress allowlist would have flagged or blocked the exfiltration traffic at the runner level. **Implement a package version cooldown.** StepSecurity's Secure Registry holds newly published package versions for a configurable window before allowing them into builds. The TanStack malicious versions existed in npm for a matter of hours before deprecation — a cooldown period would have meant most teams never pulled them. **Check your lock files now.** StepSecurity recommends checking `package-lock.json`, `pnpm-lock.yaml`, and `yarn.lock` for any compromised @tanstack versions published on May 11, 2026. If your environment ran `npm install`, `pnpm install`, or `yarn install` against an affected version on that date, GitHub's advisory is unambiguous: treat the entire install environment as compromised and rotate every secret accessible from that host — but isolate the environment before you do, given the dead-man's switch. **Understand what SLSA provenance actually guarantees.** Valid attestations mean the pipeline was legitimate. They say nothing about whether the code entering that pipeline was safe. Teams that treated SLSA as a final safety check discovered its actual scope the hard way on May 11.

What Actually Would Have Stopped This — Specific Controls, Not a Checklist

What to Watch Next

StepSecurity detected and reported the TanStack compromise within 20 minutes, which limited the blast radius significantly — GitHub published a security advisory at 21:30 UTC, roughly two hours after the first malicious publish. That response speed is genuinely impressive, but it also reveals how narrow the margin was: 84 malicious versions reached Mistral AI, UiPath, and others within that same window. Three things are worth watching as this campaign continues to evolve. First, the full blast radius of wave four is still being mapped — at the time of reporting, Socket Security had flagged 416 total packages across npm and PyPI, and the Mistral AI PyPI package was quarantined. Second, TeamPCP's use of AI coding agent persistence (targeting Claude Code and VS Code in wave three) signals that the attack surface is expanding beyond CI/CD pipelines into developer workstations in a more persistent way. Third, the fact that wave four achieved valid SLSA Build Level 3 attestations means the security community needs an honest conversation about what supply chain provenance tooling can and cannot guarantee — because right now, it's being sold as a stronger guarantee than it actually is.

What to Watch Next

Comments

No comments yet — be the first to weigh in.