Published
- 8 min read
The Silent Worm: TeamPCP Hijacks TanStack in "Mini Shai-Hulud" Attack
With over 518 million cumulative monthly downloads across the affected libraries, the software supply chain is facing an unprecedented crisis. On May 11, 2026, the threat actor known as “TeamPCP” orchestrated a massive, self-spreading worm campaign targeting both the npm and PyPI ecosystems.
Dubbed “Mini Shai-Hulud,” this attack compromised foundational packages including TanStack, UiPath, Mistral AI, OpenSearch, and Guardrails AI. But what makes this breach terrifying isn’t just its scale it’s the tradecraft. The attackers successfully bypassed traditional authentication, extracted OIDC tokens directly from CI/CD runner memory, and published malicious packages that carry valid SLSA Build Level 3 provenance attestations.
Worse, the malware lays a devastating trap for incident responders: a dead-man’s switch that transforms the stealer into a wiper if you revoke your credentials too quickly. Here is the technical breakdown of how TeamPCP pulled off the attack of the year, and the exact steps you must take to sanitize your environment without triggering a localized wipe.
For the complete list of affected packages, see Wiz’s comprehensive analysis, which includes 170+ compromised npm and PyPI packages across multiple namespaces.
What to Remember
- Valid SLSA Provenance: The compromised TanStack packages are the first documented npm worm to carry valid SLSA Build Level 3 attestations, proving that supply chain signatures are useless if the CI runner itself is poisoned.
- The “Dead-Man’s Switch” Trap: The malware installs a daemon (
gh-token-monitor) that polls GitHub every 60 seconds. Do not blindly revoke your tokens. If the token is revoked, the script executesrm -rf ~/on your machine. - Advanced C2 Evasion: The attackers use the decentralized Session messenger network to exfiltrate data, bypassing traditional enterprise DNS blocklists.
- OIDC Memory Extraction: The attackers didn’t steal long-lived npm tokens. They poisoned the GitHub Actions cache and extracted short-lived OIDC tokens directly from the
/proc/<pid>/memrunner process.
The Anatomy of a Perfect Worm: SLSA Bypass & Cache Poisoning
Most supply chain attacks rely on stealing a developer’s long-lived personal access token (PAT). TeamPCP didn’t bother. They went after the build pipeline itself.
The compromise of the @tanstack ecosystem (which includes the immensely popular @tanstack/react-router) relied on a highly sophisticated chained GitHub Actions attack.
- The Poisoned Pull Request: The attacker forked the
TanStack/routerrepository (hiding it under a renamed account) and submitted a pull request. - The
pull_request_targetExploit: The repository used the dangerouspull_request_targetworkflow trigger. This executed the workflow in the context of the base repository but checked out the attacker’s malicious code. - Cache Poisoning: The malicious PR poisoned the GitHub Actions cache with a tampered
pnpmstore. - Memory Extraction: When legitimate maintainers later merged code into
main, the release workflow restored the poisoned cache. The attacker-controlled binaries executed and dumped the GitHub Actions runner’s process memory (/proc/<pid>/mem) to extract the temporary OIDC token.
Because the attacker used the pipeline’s legitimate OIDC permissions to “mint” a short-lived publish token, the resulting malicious packages were signed with valid SLSA Build Level 3 provenance attestations. To the outside world, and to automated security scanners, these packages looked perfectly legitimate.
The Infection Vector and Triple-Threat Exfiltration
Once a developer runs npm install on a compromised package (like the 84 affected TanStack versions or the UiPath variants), a lifecycle hook (prepare or preinstall) executes a bundled setup.mjs script. This downloads the Bun runtime and executes an obfuscated, 2.3MB JavaScript payload (router_init.js).
This payload is a comprehensive credential stealer targeting AWS IMDSv2, HashiCorp Vault, Kubernetes service accounts, and cryptocurrency wallets. But its exfiltration architecture is what makes it unique. TeamPCP uses three redundant channels:
- Decentralized Evasion (Session Protocol): The primary exfiltration route sends data to
filev2.getsession[.]org. Because Session is a privacy-focused, decentralized messaging service, it is rarely blocked by enterprise firewalls. - Typosquat Fallback: It attempts to phone home to
git-tanstack[.]com. - GitHub API Dead Drops: Using stolen GitHub tokens, the malware uses the GraphQL API to create new, Dune-themed repositories (description:
"Shai-Hulud: Here We Go Again") on the victim’s account, committing the encrypted stolen credentials as files.
⚠️ The Wiper Trap: Do Not Revoke Tokens Immediately
TeamPCP knows that the standard Incident Response (IR) playbook dictates immediately revoking compromised credentials. To counter this, they weaponized the IR process itself.
If the malware finds a valid GitHub token with repository write access, it establishes persistence by installing a daemon called gh-token-monitor.
This daemon polls the api.github.com/user endpoint every 60 seconds using the stolen token. If a developer revokes the token from their GitHub dashboard, the API returns a 401 Unauthorized error. The daemon interprets this as a kill signal and immediately triggers a destructive routine: rm -rf ~/ (wiping the developer’s home directory).
Step-by-Step Remediation Walkthrough
If you suspect your machine has installed a compromised version of @tanstack, @uipath, or @mistralai, you must follow this exact order of operations to avoid the wiper.
Step 1: Isolate the Machine from the Network Disconnect from Wi-Fi or unplug the ethernet cable. This stops the daemon from communicating with GitHub and receiving a 401 error while you work.
Step 2: Hunt for and Kill the Persistence Hooks
Check for the gh-token-monitor daemon and delete it.
Command (macOS):
launchctl unload ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
rm ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
Command (Linux):
systemctl --user stop gh-token-monitor.service
rm ~/.config/systemd/user/gh-token-monitor.service
Why: You must kill the dead-man’s switch before invalidating the token.
Step 3: Audit IDE Directories for Runtime Artifacts The malware establishes secondary persistence hooks in your IDE folders to re-infect you upon reboot. Command:
find ~/.vscode ~/.claude -name "router_runtime.js" -o -name "setup.mjs" -type f -delete
Step 4: Rotate Credentials Only after steps 1-3 are complete should you log into your cloud providers (from a different, clean device) and rotate your AWS keys, GitHub tokens, npm publish tokens, and Kubernetes service accounts.
The Python PyPI Variant: Geofenced Destruction
While the npm ecosystem suffered the brunt of the attack, PyPI was not spared. Packages like guardrails-ai@0.10.1 and mistralai@2.4.6 were infected.
The Python variant executes upon import. Instead of a massive obfuscated file, it contains 13 lines of code that download a payload from git-tanstack[.]com/tmp/transformers.pyz.
This variant includes highly specific, geofenced logic:
- Russian Language Bypass: If the system is configured for the Russian language, the malware exits silently.
- Geofenced Wiper: If the system timezone and language indicate it is located in Israel or Iran, the malware invokes
random.randint(1,6). If it rolls a 2, it plays an mp3 file at full volume and attempts to runrm -rf /to destroy the entire file system.
Lessons Learned: Redefining Supply Chain Defense
- Lesson 1:
pull_request_targetis a loaded gun. TanStack’s compromise proves that executing workflows in the context of the base repo while checking out untrusted fork code leads directly to cache poisoning and OIDC theft. What should happen: Never usepull_request_targetunless strictly necessary, and never combine it with an untrusted code checkout. - Lesson 2: SLSA is only as secure as the runner. The attackers achieved valid SLSA Level 3 attestations because they hijacked the legitimate identity of the runner. What should happen: Organizations must monitor behavioral anomalies during builds, not just cryptographic signatures after the fact.
- Lesson 3: Blind revocation is dangerous. Threat actors are actively anticipating standard IR playbooks. What should happen: IR teams must analyze the malware’s local behavior (identifying dead-man’s switches) before initiating mass credential revocation.
Conclusion
The “Mini Shai-Hulud” campaign by TeamPCP is a masterclass in modern software supply chain exploitation. This attack follows a series of high-profile compromises attributed to the same actor, including the hijacking of Trivy and LiteLLM. We are also seeing the evolution of these tactics in the emerging Shai-Hulud 2.0 recursive infection models.
By combining GitHub Actions cache poisoning, OIDC memory extraction, decentralized C2 exfiltration, and a punitive wiper script, they have elevated the baseline of what defenders must protect against.
Security teams can no longer rely solely on static analysis or package signatures. You must enforce strict egress filtering on your CI/CD runners, disable automatic preinstall script execution, and actively monitor the runtime behavior of your build environments.
To further enhance your cloud security and implement Zero Trust, contact me on LinkedIn Profile or contact@ogw.fr.
Indicators of Compromise (IOCs)
Security teams should use these IOCs to detect and respond to Mini Shai-Hulud infections:
File Hashes
| File | Size | Hash Type | Hash Value |
|---|---|---|---|
| router_init.js | 2,341,681 bytes | SHA256 | ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266c |
| router_init.js | 2,339,346 bytes | SHA256 | 2ec78d556d696e208927cc503d48e4b5eb56b31abc2870c2ed2e98d6be27fc96 |
| router_init.js | 2,339,346 bytes | SHA1 | e7d582b98ca80690883175470e96f703ef6dc497 |
| setup.mjs | 5,047 bytes | SHA256 | 2258284d65f63829bd67eaba01ef6f1ada2f593f9bbe41678b2df360bd90d3df |
| setup.mjs | 5,047 bytes | SHA1 | 12f35b1081b17d21815b35feb57ab03d02482116 |
| Trojanized tarball | — | SHA256 | 1e8538c6e0563d50da0f2e097e979ebd5294ce1defe01d0b9fe361ba3bed1898 |
| opensearch_init.js | — | SHA1 | 820fa07a7328b6cf2b417078e103721d4d8f2e79 |
Network Indicators
| Type | Indicator | Purpose |
|---|---|---|
| Domain | git-tanstack.com | Primary C2 infrastructure |
| Payload URL | git-tanstack.com/tmp/transformers.pyz | PyPI variant payload delivery |
| Session Seed Node | seed1.getsession.org | Decentralized message routing |
| Session Seed Node | seed2.getsession.org | Decentralized message routing |
| Session Seed Node | seed3.getsession.org | Decentralized message routing |
| Session File Server | filev2.getsession.org | Credential exfiltration endpoint |
| Session Recipient ID | 05f9e609d79eed391015e11380dee4b5c9ead0b6e2e7f0134e6e51767a87323026 | Attacker’s decentralized inbox |
| C2 IP Address | 83.142.209.194 | PyPI variant exfiltration server |
System Indicators
| Indicator | Location | Platform |
|---|---|---|
| gh-token-monitor | ~/Library/LaunchAgents/com.user.gh-token-monitor.plist | macOS |
| gh-token-monitor | ~/.config/systemd/user/gh-token-monitor.service | Linux |
| router_runtime.js | ~/.vscode/ or ~/.claude/ | IDE persistence |
| tanstack_runner.js | ~/.vscode/ or ~/.claude/ | IDE persistence |
| Preinstall hook | package.json | node setup.mjs |
| Git dependency | package.json | github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c |
Frequently Asked Questions (FAQ)
What is the Mini Shai-Hulud supply chain attack?
It is a massive supply chain compromise by the threat actor TeamPCP, infecting over 170 npm and PyPI packages. It operates as a self-spreading worm that steals credentials and leverages compromised OIDC tokens to publish more malicious packages.
How did TeamPCP bypass SLSA provenance checks?
The attackers used a GitHub Actions 'pull_request_target' exploit to poison the build cache. They then extracted OIDC tokens from the runner's memory to mint short-lived publish tokens, resulting in malware signed with legitimate SLSA Level 3 attestations.
Why should I wait before revoking my GitHub tokens if compromised?
The malware installs a dead-man's switch daemon ('gh-token-monitor') that checks if your token is valid every 60 seconds. If it detects you have revoked the token, it immediately executes a destructive command to wipe your home directory.
How does the malware communicate with its C2 servers?
To evade traditional DNS blocking, the malware uses a triple-threat architecture: typosquat domains (git-tanstack[.]com), the decentralized Session messaging network (*.getsession.org), and GitHub API dead drops via stolen tokens.
What makes the Python variant (like Mistral AI) different?
The PyPI payload executes on 'import' and downloads a remote Python artifact. It features geofenced logic that bypasses Russian-language systems and includes a 1-in-6 chance of executing a destructive wiper if the machine is located in Israel or Iran.