TeamPCP's npm Worm Hits Mistral AI SDK, TanStack, and 170 Packages in 6 Minutes — With Fake Provenance
At 19:20 UTC on May 11, 2026, a self-propagating npm worm began publishing malicious package versions across 42 TanStack namespaces. Six minutes later, 84 compromised artifacts were live. Within hours, the campaign had spread to Mistral AI’s npm and PyPI packages, UiPath, the AWS-maintained OpenSearch JavaScript client, Guardrails AI, and over a dozen other namespaces. By the time npm quarantine ran, 373 malicious versions across 169 package names were in the wild.
TeamPCP, the threat group attributed by StepSecurity, named the campaign “Mini Shai-Hulud.” It has been assigned CVE-2026-45321 with a CVSS score of 9.6 Critical.
What the Worm Did
The entry point was not a phished maintainer credential. It was an orphaned commit in a TanStack CI workflow that still had OIDC trust federation configured with npm. The attacker extracted an OIDC token from the GitHub Actions runner process mid-execution, then exchanged it for authenticated publish access to the entire TanStack namespace.
Every infected CI run became a new publisher. Each compromised version carried a preinstall hook that downloaded the Bun JavaScript runtime, then launched a 2.3 MB obfuscated payload (router_init.js). The payload swept CI secrets, cloud credentials, Kubernetes service account tokens, and Vault secrets. On runners with active OIDC federation, it minted fresh npm tokens and republished infected versions under stolen maintainer identities.
The packages it reached:
| Namespace | Versions | Weekly Downloads |
|---|---|---|
| @tanstack/react-router | 1.169.5, 1.169.8 | 12.7M |
| @opensearch-project/opensearch | 3.5.3–3.8.0 | 1.3M |
| @mistralai/mistralai | 2.2.2–2.2.4 (npm + PyPI) | — |
| @uipath | 66 versions | — |
| guardrails-ai | 0.10.1 (PyPI) | — |
| @squawk | 87 versions | — |
The SLSA Problem
The technically significant detail is not the scale. Wave two of the Shai-Hulud campaign in November 2025 compromised 492 packages and 25,000 repositories. What makes wave four different: for the first time, the malicious packages were published with valid SLSA Build Level 3 provenance attestations.
SLSA Build Level 3 provenance is generated by Sigstore — Fulcio certificate authority, Rekor transparency log, in-toto attestations. The provenance signature is meant to be a final trust anchor: proof that a package was built from a specific source commit using a trusted pipeline. TeamPCP’s worm produced these certificates legitimately, because it hijacked the legitimate build pipeline itself. Sigstore verified the process correctly. SLSA does not verify that the code being built was safe.
This is a category escalation. Defenders who’ve moved beyond “lock down credentials” to “verify provenance” now have a documented attack that defeats that layer too.
AI Tool Persistence
One operational detail that matters for AI developer environments: exfiltration ran through the Session P2P messaging network, not standard HTTP C2. The traffic is encrypted IM protocol, indistinguishable from legitimate messaging at the network layer.
Persistence was planted in two locations that standard npm uninstall does not touch: Claude Code hook directories (.claude/settings.json) and VS Code task runners (.vscode/tasks.json). On systems where Claude Code or VS Code is invoked regularly, the worm fires again on every tool invocation until those hook files are explicitly removed.
This is the third consecutive TeamPCP campaign to use AI developer tooling as a persistence surface. Wave three in April targeted .claude/settings.json explicitly. The Mistral AI SDK compromise means the attack is now inside the client libraries that AI applications call directly.
What Teams Should Do
Any team that ran npm install on a @tanstack, @mistralai, or @opensearch-project package between May 11 19:20 UTC and npm quarantine should treat the install environment as compromised. Rotate every secret accessible from that host — npm tokens, GitHub tokens, cloud credentials, Kubernetes service accounts. Check for .claude/settings.json and .vscode/tasks.json entries that were not explicitly set by your team.
The full affected package list, with specific version numbers and remediation steps, is published by Snyk (CVE-2026-45321) and Aikido Security.