⬤ ACTIVE THREAT | CVE-2026-45321 · CVSS 9.6 CRITICAL | MINI SHAI-HULUD — SUPPLY CHAIN WORM | TANSTACK ECOSYSTEM COMPROMISED | MAY 11, 2026
WORM
⬤ CRITICAL CVSS 9.6 CVE-2026-45321 GHSA-g7cv-rxg3-hmpx MAY 11, 2026

MINI
SHAI-HULUD

// SELF-PROPAGATING SUPPLY CHAIN WORM — @TANSTACK NPM ECOSYSTEM
// TL;DR — READ THIS FIRST

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.

170+
packages compromised
12M
weekly downloads at risk
84
malicious versions published
6
minutes to publish all 84
01 —

WHAT HAPPENED & WHEN

MAY 11 · 19:20 UTC
Attacker submits malicious PR to TanStack repo, poisoning GitHub Actions build cache with 1.1 GB of compromised deps
MAY 11 · 19:26 UTC
84 malicious package versions across 42 @tanstack packages published in 6 minutes using stolen OIDC tokens
MAY 11 · EVENING
Worm propagates autonomously to @mistralai, @uipath, OpenSearch, and 100+ other packages using tokens stolen from victim CI/CD
MAY 12 · 11:00 UTC
Security researchers publish initial IOCs; compromised packages identified and unpublished from npm registry
MAY 13 · 14:30 UTC
Analysis finds some worm-propagated packages had bugs rendering payload non-functional in @uipath and @mistralai
02 —

HOW IT GOT IN: 3 CHAINED EXPLOITS

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.

EXPLOIT 01

PR TARGET ATTACK

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.

→
EXPLOIT 02

CACHE POISONING

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.

→
EXPLOIT 03

OIDC TOKEN HIJACK

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.

→
RESULT

SIGNED MALICIOUS RELEASE

Used the valid OIDC token + Sigstore stack to publish malicious versions with SLSA Build Level 3 attestation. npm saw them as legitimate, signed packages.

⚡ WHY THIS IS UNPRECEDENTED

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.

03 —

WHAT THE MALWARE DOES TO YOU

🔑

CREDENTIAL HARVEST

Steals everything it can find on the machine and in the CI/CD environment the moment the package is installed.

GitHub Actions Tokens AWS IAM + IMDSv2 GCP Credentials Azure Tokens HashiCorp Vault Kubernetes Service Accounts npm Publish Tokens SSH Keys ~/.claude/projects/*.jsonl
📡

TRIPLE C2 EXFILTRATION

Three redundant channels ensure stolen data reaches the attacker even if one path is blocked.

git-tanstack[.]com — typosquat Session/Oxen P2P Messenger GitHub GraphQL API dead-drop

The GitHub dead-drop technique bypasses network egress policies — GitHub traffic is rarely blocked in corporate environments.

🐛

SELF-PROPAGATION (WORM)

With stolen npm tokens, the worm queries all packages maintained by the victim and republishes poisoned versions — spreading autonomously with no further attacker input.

@mistralai/mistralai @uipath/* (40+ pkgs) @opensearch-project 19 Squawk packages 100+ additional packages
💣

DESTRUCTIVE FAILSAFE

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.

// PERSISTENCE IMPLANTS DROPPED ON VICTIM MACHINES
LINUX — SYSTEMD
~/.config/systemd/user/
gh-token-monitor.service
MACOS — LAUNCHAGENT
~/Library/LaunchAgents/
com.user.gh-token-monitor.plist
EDITOR HOOKS
.claude/router_runtime.js
.vscode/setup.mjs
.github/workflows/codeql_analysis.yml
04 —

AFFECTED PACKAGES

These exact @tanstack versions are confirmed malicious. Any other version is safe from this specific attack.

@tanstack/react-router 1.169.5  ·  1.169.8
@tanstack/vue-router 1.169.5  ·  1.169.8
@tanstack/solid-router 1.169.5  ·  1.169.8
@tanstack/router-core 1.169.5  ·  1.169.8
@tanstack/react-start 1.167.68  ·  1.167.71
@tanstack/router-plugin 1.167.38  ·  1.167.41

+36 additional @tanstack/* packages — full list in GHSA-g7cv-rxg3-hmpx

✓ CONFIRMED UNAFFECTED FAMILIES

@tanstack/query*  ·  @tanstack/table*  ·  @tanstack/form*  ·  @tanstack/virtual*  ·  @tanstack/store — these were NOT compromised in this attack.

05 —

HOW TO DETECT

Run on developer machines, CI/CD runners, and any host that built with TanStack packages during the window.

// CHECK 1 — LOOK FOR MALICIOUS FILE IN node_modules
find . -name 'router_init.js' -size +1M # Any result = compromised. Isolate the machine immediately.
// CHECK 2 — SCAN LOCKFILE FOR KNOWN BAD COMMIT SHA
grep -r '79ac49eedf774dd4b0cfa308722bc463cfe5885c' package-lock.json # Match = malicious github: optional dependency marker present in lockfile
// CHECK 3 — PERSISTENCE DAEMON (run before rotating ANY tokens)
# Linux: systemctl --user status gh-token-monitor.service # macOS: ls ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
// CHECK 4 — SCAN FOR DROPPED PAYLOAD FILES
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
// INDICATORS OF COMPROMISE
TYPEVALUE
Malicious filerouter_init.js — 2.3MB obfuscated payload in package root
File SHA-256ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266c
C2 domaingit-tanstack[.]com
C2 networkfilev2.getsession[.]org (Session messenger)
Lockfile markergithub:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c
Attacker forkgithub.com/zblgg/configuration
Daemon (Linux)~/.config/systemd/user/gh-token-monitor.service
Daemon (macOS)~/Library/LaunchAgents/com.user.gh-token-monitor.plist
06 —

MITIGATION STEPS

⚠

DO THIS BEFORE REVOKING ANY CREDENTIALS

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.

01

KILL THE WATCHDOG DAEMON FIRST

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
02

REMOVE INJECTED PAYLOAD FILES

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
03

ROTATE ALL CREDENTIALS IN ORDER

Treat every secret accessible from the compromised machine as stolen. Rotate in this priority sequence:

PRIORITY 1

npm publish tokens
OIDC grants
GitHub App tokens

PRIORITY 2

GitHub PATs
AWS IAM keys
Vault tokens

PRIORITY 3

Kubernetes service accounts
GCP + Azure credentials
SSH keys

04

UPDATE TANSTACK PACKAGES

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
05

BLOCK C2 INFRASTRUCTURE

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
06

HARDEN AGAINST FUTURE ATTACKS

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.

07 —

COMMON QUESTIONS

Q
My TanStack packages are all on versions from before May 10, 2026. Am I safe?
+
✓ YOU ARE SAFE FROM THIS ATTACK

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.

Q
What happens if I update my TanStack packages today (May 21, 2026)?
+
✓ UPDATING TODAY IS SAFE

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
Q
Which CI/CD setups are exposed to this risk? GitHub Actions? Jenkins? What if I don't use CI/CD at all?
+

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.

⬤ GITHUB ACTIONS — HIGHEST RISK
The attack was built specifically to exploit GitHub Actions OIDC. If your pipeline publishes to npm via GitHub Actions, the worm could steal your OIDC token and publish compromised versions of your packages to other developers. If you only build (no npm publish), risk is credential theft only.
⬤ GITLAB CI / CIRCLECI — MEDIUM RISK
The payload targeted GitLab and CircleCI tokens for credential theft. Worm propagation is less likely without a GitHub Actions OIDC token, but any secrets on the runner (AWS, Vault, npm tokens) are still at risk if a compromised package was installed.
⬤ JENKINS — LOWER WORM RISK
Jenkins doesn't use GitHub Actions OIDC, so the worm propagation vector doesn't apply. However, if 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.
⬤ NO CI/CD — LOCAL DEV ONLY
Still at risk if you ran 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.

Q
What is a supply chain attack? Explain it simply.
+
// REAL WORLD ANALOGY

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.

// HOW A NORMAL INSTALL WORKS VS. WHAT HAPPENED HERE
TanStack devs
write code
→
GitHub Actions
build pipeline
⚠ POISONED HERE
→
npm registry
malicious pkg
looks legit ✓ signed
→
npm install
in your app
malware runs
→
your CI/CD
credentials stolen
worm spreads

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.