A threat group called TeamPCP planted a self-replicating worm
inside 42 @tanstack npm packages on May 11, 2026.
The malware steals CI/CD tokens, cloud credentials, and SSH keys — then
automatically re-publishes itself to more packages using those stolen tokens.
If you installed an affected @tanstack/react-router,
@tanstack/router-core, or related package
between May 11–12, 2026, treat your machine and CI/CD pipeline as compromised.
Three vulnerabilities chained together let the attacker publish malicious packages using TanStack's own legitimate signing keys — producing cryptographic provenance attestation that npm security checks could not distinguish from real releases.
Attacker forked TanStack repo and opened a PR that triggered a pull_request_target workflow. This workflow runs in the base repo's security context — not the fork's — giving the fork access to secrets.
Fork code poisoned the pnpm package store cache (1.1 GB of compromised deps), pre-computing the exact cache key the legitimate release workflow would query hours later.
Injected build artifacts read /proc/<pid>/mem on the GitHub Actions runner to extract the live OIDC token from runner memory — without stealing any npm credentials directly.
Used the valid OIDC token + Sigstore stack to publish malicious versions with SLSA Build Level 3 attestation. npm saw them as legitimate, signed packages.
Previous supply chain attacks could be caught by checking provenance: was this package actually built from the official repo? Mini Shai-Hulud is the first documented attack to produce valid SLSA Build Level 3 provenance for malicious packages — because it hijacked the legitimate build pipeline itself, not just stolen credentials. Cryptographic provenance attestation alone is no longer sufficient as a trust signal.
Steals everything it can find on the machine and in the CI/CD environment the moment the package is installed.
Three redundant channels ensure stolen data reaches the attacker even if one path is blocked.
The GitHub dead-drop technique bypasses network egress policies — GitHub traffic is rarely blocked in corporate environments.
With stolen npm tokens, the worm queries all packages maintained by the victim and republishes poisoned versions — spreading autonomously with no further attacker input.
Installs a dead-man's switch daemon that polls GitHub every 60 seconds with stolen tokens. If it detects credential revocation before you remove it:
rm -rf ~/
⚠ This destroys your entire home directory. Remove the daemon BEFORE revoking any tokens.
~/.config/systemd/user/
gh-token-monitor.service
~/Library/LaunchAgents/
com.user.gh-token-monitor.plist
.claude/router_runtime.js
.vscode/setup.mjs
.github/workflows/codeql_analysis.yml
These exact @tanstack versions are confirmed malicious.
Any other version is safe from this specific attack.
+36 additional @tanstack/* packages — full list in GHSA-g7cv-rxg3-hmpx
@tanstack/query* · @tanstack/table* · @tanstack/form* · @tanstack/virtual* · @tanstack/store — these were NOT compromised in this attack.
Run on developer machines, CI/CD runners, and any host that built with TanStack packages during the window.
find . -name 'router_init.js' -size +1M
# Any result = compromised. Isolate the machine immediately.
grep -r '79ac49eedf774dd4b0cfa308722bc463cfe5885c' package-lock.json
# Match = malicious github: optional dependency marker present in lockfile
# Linux:
systemctl --user status gh-token-monitor.service
# macOS:
ls ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
ls .claude/router_runtime.js .claude/setup.mjs 2>/dev/null
ls .vscode/setup.mjs ~/.local/bin/gh-token-monitor.sh 2>/dev/null
git log --all -- .github/workflows/codeql_analysis.yml
| TYPE | VALUE |
|---|---|
| Malicious file | router_init.js — 2.3MB obfuscated payload in package root |
| File SHA-256 | ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266c |
| C2 domain | git-tanstack[.]com |
| C2 network | filev2.getsession[.]org (Session messenger) |
| Lockfile marker | github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c |
| Attacker fork | github.com/zblgg/configuration |
| Daemon (Linux) | ~/.config/systemd/user/gh-token-monitor.service |
| Daemon (macOS) | ~/Library/LaunchAgents/com.user.gh-token-monitor.plist |
The malware installs a dead-man's switch that runs rm -rf ~/
the moment it detects credential revocation. If you skip Step 1 and rotate
tokens first, you will permanently destroy your home directory.
Remove the daemon first. Every time.
This must be done before any other step. Disarm the dead-man's switch before touching credentials.
# Linux:
systemctl --user stop gh-token-monitor.service
systemctl --user disable gh-token-monitor.service
rm -f ~/.config/systemd/user/gh-token-monitor.service
# macOS:
launchctl unload ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
rm -f ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
Clean up dropped files in editor config directories and CI/CD workflow files.
rm -f .claude/router_runtime.js .claude/setup.mjs
rm -f .vscode/setup.mjs
rm -f ~/.local/bin/gh-token-monitor.sh
# Review injected GitHub Actions workflows:
git log --all -- .github/workflows/codeql_analysis.yml
# Verify .claude/settings.json for hook injections
Treat every secret accessible from the compromised machine as stolen. Rotate in this priority sequence:
npm publish tokens
OIDC grants
GitHub App tokens
GitHub PATs
AWS IAM keys
Vault tokens
Kubernetes service accounts
GCP + Azure credentials
SSH keys
Move off the compromised versions immediately. The latest releases have been verified clean.
# Update affected router packages:
npm update @tanstack/react-router @tanstack/router-core
npm update @tanstack/react-start @tanstack/router-plugin
# Purge and reinstall to remove cached bad versions:
rm -rf node_modules package-lock.json && npm install
Add to your DNS blocklist or firewall to cut ongoing exfiltration channels.
# Block at DNS/proxy/firewall level:
git-tanstack[.]com
*.getsession.org
api.masscan.cloud
These settings prevent most install-time supply chain attacks going forward.
# ~/.npmrc — add these lines:
ignore-scripts=true # block postinstall script execution
min-release-age=7 # reject packages published < 7 days ago
allow-git=none # block git:// protocol dependencies
Also: pin all GitHub Actions references to commit SHAs (not tags), audit all pull_request_target workflows in your repos for cache poisoning risks, and purge all existing GitHub Actions caches.
The malicious versions were published on May 11, 2026.
If your package-lock.json or yarn.lock
shows versions dated before that — you never pulled the poisoned packages.
Your machine and CI/CD were not exposed to this specific worm.
One thing to verify: check that your lockfile was not
auto-updated by a CI run or npm install between May 11–12 without you noticing.
Run git log package-lock.json and check if there was any lockfile change in that window.
If the lockfile didn't change during May 11–12 → you're clear.
Regardless, it's a good time to update to latest clean versions. No urgency, no incident — just routine maintenance.
The compromised versions were pulled from the npm registry within ~24 hours of discovery,
by May 12, 2026. The current latest tag on all
TanStack packages points to verified-clean versions.
Running npm update @tanstack/react-router today will install
a clean, post-incident release. The TanStack team has also reviewed and hardened their
GitHub Actions workflows since the incident.
Recommended: wipe node_modules and
reinstall fresh rather than doing an incremental update, just to ensure no
cached artifacts from the compromised window persist locally.
rm -rf node_modules package-lock.json
npm install
Risk differs significantly based on your CI/CD setup. The worm was specifically engineered to spread via GitHub Actions OIDC tokens — but credential theft affects everyone.
npm install
ran a compromised version on Jenkins, all credentials in that environment
are at risk — npm tokens, AWS keys, Vault tokens stored as env vars or on disk.
npm install
locally during May 11–12. The malware harvests developer machine credentials too:
SSH keys, GitHub tokens, ~/.aws/credentials,
and even Claude Code session files. The worm propagation aspect is less relevant
since you likely don't publish packages.
Key rule: the risk of being a victim (credential theft) applies to
anyone who ran npm install with a compromised version.
The risk of becoming a vector (spreading the worm to your users) applies
specifically if you publish npm packages via GitHub Actions.
Imagine a restaurant that buys pre-cut vegetables from a supplier. Instead of breaking into the restaurant's kitchen, an attacker bribes someone at the vegetable factory to add poison to the bags before they're shipped. The bags arrive looking normal. The restaurant trusts the supplier like always. The poison gets cooked into every dish. By the time anyone notices, it's already been served.
In software: your app depends on packages from npm. You trust those packages are exactly what their authors wrote. A supply chain attack poisons the package at the source — before it reaches you — so your normal security checks don't catch it, because from the outside, everything looks legitimate.
What made this specific attack especially dangerous: normally you can verify a package's provenance — was it really built from the official repo? Here, the attacker hijacked the actual build pipeline, so the cryptographic signature was genuinely valid. There was no way for a developer to tell the difference by looking at the package.
This is why supply chain attacks are considered one of the most dangerous threat vectors in modern software: they weaponize trust itself. You're not being tricked into downloading something suspicious. You're downloading exactly what you always download — but it's been poisoned upstream.