
TanStack — the JavaScript framework family powering millions of React apps — had 42 packages compromised in a six-minute attack window on May 11. If you installed anything from the @tanstack/router family that day, your AWS keys, GitHub tokens, and even your 1Password vault may already be in an attacker’s hands. The group behind this has now run five of these attacks in eight months. What makes this one different: it produced validly-signed, SLSA-attested malicious packages, breaking the developer assumption that signed and attested means safe.
What Happened
Between 19:20 and 19:26 UTC on May 11, threat group TeamPCP published 84 malicious versions across 42 @tanstack/* packages. It did not stop there. The same self-spreading worm then propagated to 65 UiPath packages, the Mistral AI SDK on both npm and PyPI, the Guardrails AI PyPI package, the OpenSearch JavaScript client, and more — 170 packages in total, representing 518 million cumulative downloads across the affected ecosystem.
The attack was detected within 20 minutes by an external security researcher at StepSecurity. Response was fast. But fast detection does not help if you had already run an install during that six-minute window.
Why SLSA Provenance Did Not Save TanStack
TanStack had done everything right. Every npm release carried signed SLSA Build Level 3 provenance attestations. Maintainer accounts had 2FA enabled. Publishing used OIDC trusted publishing instead of long-lived npm tokens. On paper, this project was a model for secure open-source infrastructure.
It did not matter. This is the first documented npm worm to produce validly-attested malicious packages. The attack did not forge a signature — it compromised the CI pipeline that generates legitimate signatures, then used that pipeline’s own OIDC token to publish. SLSA provenance confirms which pipeline produced a package. It does not confirm that the pipeline was behaving as intended, that it ran from a protected branch, or that no attacker-controlled code ran inside it.
The lesson: provenance attestation is one layer of a defense stack, not the whole stack.
How the Attack Worked
The technique combined three components: the pull_request_target GitHub Actions trigger, cache poisoning across the fork/base trust boundary, and OIDC token extraction from runner process memory.
The attacker forked TanStack/router and renamed the fork to zblgg/configuration to hide it from fork-list searches. Opening a pull request triggered a pull_request_target workflow — one that runs in the context of the base repository, not the fork, meaning it has access to repository secrets and can write to the Actions cache even from external contributor PRs. The malicious PR code wrote a poisoned 1.1 GB pnpm store cache entry, then the PR was quietly reverted and closed.
The cache sat poisoned. Days later, a legitimate maintainer merged an unrelated PR. The release workflow ran, restored the poisoned cache, and attacker-controlled binaries executed inside the trusted CI context. Those binaries extracted a short-lived OIDC token directly from the runner’s process memory (/proc/<pid>/mem) and used it to publish 84 malicious package versions in six minutes.
The dangerous workflow pattern looks like this:
# Vulnerable: pull_request_target with cache auto-save
on:
pull_request_target:
jobs:
build:
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }} # DANGEROUS: checks out fork code
- uses: actions/cache@v5 # auto-saves — writable from fork context
with:
path: ~/.pnpm-store
What the Worm Steals
The payload — a 2.3 MB obfuscated JavaScript file — targets over 100 hardcoded credential paths: AWS, GCP, Azure, Kubernetes, HashiCorp Vault, GitHub personal access tokens, npm tokens, SSH keys, CI/CD pipeline credentials, and crypto wallets. In this fifth wave, the worm added 1Password and Bitwarden to its target list for the first time. Your password manager is now part of the attack surface.
After harvesting credentials, the worm uses the stolen GitHub and npm tokens to find other packages the compromised maintainer owns, then publishes malicious versions to those too. That is how Mistral AI and UiPath ended up in this incident — their maintainers’ credentials were harvested from a TanStack developer environment.
What to Do If You Were Affected
The safe @tanstack families — @tanstack/query*, @tanstack/table*, @tanstack/form*, @tanstack/virtual*, and @tanstack/store — were not compromised. The affected packages are the router family. To check without executing scripts:
npm pack @tanstack/react-router@1.169.5 --dry-run
# Inspect the tarball and grep for optionalDependencies in package.json
# A legitimate release will not have this field added unexpectedly
If you installed an affected version on May 11, take these steps in order:
- Remove the persistence daemon first. Search for the
gh-token-monitorprocess and stop it before revoking any GitHub tokens. The worm installs this daemon to detect token revocation and trigger a wiper payload. Revoke tokens while it is running and you risk losing the environment. - Rotate all credentials reachable from the affected host: AWS, GCP, Kubernetes, Vault, GitHub, npm, and SSH keys.
- Audit your GitHub Actions workflows for the
pull_request_target+ cache write pattern. Replaceactions/cache@v5withactions/cache/restorefor restore-only semantics, and pin all actions to a commit SHA rather than a tag.
The Pattern Is Not Stopping
This is the fifth Shai-Hulud wave in eight months. Each iteration has expanded scope: new credential targets, new package ecosystems, and now SLSA attestation bypass. The attacks are automated, targeted, and cross-ecosystem — npm and PyPI in the same campaign, in the same six-minute window.
Supply chain security is not a solved problem. Every package your project depends on is a potential attack surface, and that surface extends through the CI/CD pipelines of every maintainer in your dependency graph. Provenance helps. Pinning helps. Neither is sufficient alone. The gap between “we did everything right” and “we got hit anyway” is now disturbingly small.
TanStack has published a full postmortem and a hardening guide. StepSecurity’s technical analysis covers the GitHub Actions vector in depth. Snyk’s breakdown includes the full list of compromised package versions. If you maintain an open-source project with GitHub Actions CI/CD, read all four.













