Mini Shai-Hulud npm Worm Hits TanStack, Mistral AI (2026)

TeamPCP's Mini Shai-Hulud npm worm compromised 170+ packages including TanStack, Mistral AI, and Guardrails AI. Critical advisory and remediation steps.

Updated on
Mini Shai-Hulud npm Worm Hits TanStack, Mistral AI (2026)

Key Takeaways

Last updated: May 12, 2026. This story is still developing. We will update this article as new indicators of compromise and remediation guidance are published.

  • What it is: A coordinated supply chain attack on May 11, 2026 compromised 170+ npm and PyPI packages — including 42 TanStack packages, Mistral AI's official client, Guardrails AI, OpenSearch, UiPath, and Squawk — assigned CVE-2026-45321 with a critical CVSS score of 9.6.
  • What makes it new: This is the first documented npm worm to publish malicious packages carrying valid SLSA Build Level 3 provenance attestations, and the first wave to use AI coding agent configuration files (Claude Code's .claude/settings.json, VS Code's .vscode/tasks.json) as a persistence mechanism.
  • The remediation trap: The malware installs a dead-man's switch that runs rm -rf ~/ when your GitHub token is revoked. Kill the daemon before you rotate any credentials.

What Just Happened

On the evening of May 11, 2026, between 19:20 and 19:26 UTC, attackers published 84 malicious package artifacts across 42 packages in the @tanstack namespace on npm. The packages were not pushed by an attacker who stole credentials. They were published by TanStack's own legitimate release pipeline, using its trusted OIDC identity, after attacker-controlled code hijacked the GitHub Actions runner mid-workflow.

Within hours the worm self-propagated. Affected scopes now include @uipath, @mistralai/mistralai on both npm and PyPI, @opensearch-project/opensearch, the guardrails-ai Python package, multiple @squawk packages, and others. As of May 12, more than 170 packages totaling 518 million cumulative downloads have been documented as compromised, with 400+ exfiltration repositories created on victim GitHub accounts.

The campaign is attributed by StepSecurity, Wiz, and Snyk with high confidence to TeamPCP, the same actor MG has covered in the Trivy compromise that breached Cisco and the LiteLLM supply chain attack earlier this spring. The compromise has been assigned CVE-2026-45321 with a CVSS score of 9.6. The canonical advisory is GHSA-g7cv-rxg3-hmpx.

The Three Things That Make This Attack Different

Mini Shai-Hulud is the fourth wave in the broader Shai-Hulud lineage that began in September 2025. Each wave has evolved technically. Three features of this wave are genuinely new and structurally important.

1. Valid SLSA provenance on malicious packages

Per Snyk's analysis, this is the first documented supply chain attack to publish malicious packages indistinguishable from legitimate ones by provenance attestation. The cryptographic certificate that Sigstore generates to verify a package was built from a trusted source — long pitched as the supply chain security fix — is intact and correct on every compromised TanStack version. The attestations correctly state that the packages were built and published by release.yml running on refs/heads/main in the TanStack/router repository. Because the attacker hijacked the legitimate workflow's OIDC token rather than stealing publishing credentials, npm audit signatures returns clean.

The lesson: provenance verification answers "did the official pipeline produce this artifact?" It does not answer "was the pipeline run trustworthy?" Those are different questions, and the industry has been conflating them.

2. AI coding agents weaponized as persistence

The payload commits two files into every repository the stolen tokens can write to: a .claude/settings.json file abusing Claude Code's SessionStart hook, and a .vscode/tasks.json file with "runOn": "folderOpen". Both are legitimate features of legitimate tools. Both fire automatically when a developer opens the repository in Claude Code or VS Code respectively, silently re-executing the dropper.

This is the first npm worm at scale to use AI coding agent configuration as an infection vector. Anthropic flagged the SessionStart hook attack surface in anthropics/claude-code#49778 roughly two weeks before this campaign began. The VS Code project filed a parallel issue (microsoft/vscode#309406) about tasks.json folderOpen sixteen days before the campaign. Both issues describe legitimate features whose security model assumes the repository being opened is trusted.

The behavioral implication is significant. If you treat .github/workflows/ as supply chain attack surface in PR review — and you should — then .claude/, .vscode/, and your MCP server configuration files belong in the same review category. They are part of the supply chain now. For background on Claude Code's local execution model and the broader attack surface, see our two-part coverage of the Claude Code source leak and the architecture deep dive.

3. The dead-man's switch

If the malware finds a valid GitHub personal access token or OAuth token in your environment, it installs a persistent daemon. On Linux that is a systemd user service at ~/.config/systemd/user/gh-token-monitor.service running ~/.local/bin/gh-token-monitor.sh. On macOS it is a LaunchAgent at ~/Library/LaunchAgents/com.user.gh-token-monitor.plist.

The daemon polls api.github.com/user every 60 seconds with the stolen token. If GitHub returns an HTTP 40x — which is what happens when you revoke the token in your incident response — the daemon executes rm -rf ~/, attempting to delete the developer's entire home directory. The daemon auto-exits after 24 hours if it has not been triggered.

Separately, Microsoft's analysis of the mistralai PyPI package documents a probabilistic destructive branch: on systems whose timezone and locale fingerprint as Israeli or Iranian, the payload has a 1-in-6 chance of attempting rm -rf /. The malware also exits cleanly if the system locale is Russian, a CIS-exemption pattern consistent with Russian or CIS-based operator origin.

Confirmed Compromised Packages

The list below is a sample for orientation. The authoritative full list is in GHSA-g7cv-rxg3-hmpx and is being updated as more compromised artifacts are identified.

Package Compromised Versions Ecosystem
@tanstack/react-router Multiple versions, May 11 19:20–19:26 UTC npm
@tanstack/react-start Multiple versions, May 11 19:20–19:26 UTC npm
@mistralai/mistralai Multiple versions npm
mistralai 2.4.6 PyPI
guardrails-ai 0.10.1 PyPI
@opensearch-project/opensearch 3.5.3, 3.6.2, 3.7.0, 3.8.0 npm
@uipath/apollo-core and related 65 affected packages reported npm
@squawk/mcp, @squawk/weather, @squawk/flightplan 0.9.5, 0.5.10, 0.5.6 respectively npm

Confirmed clean within TanStack: Per Snyk's tracking, the @tanstack/query*, @tanstack/table*, @tanstack/form*, @tanstack/virtual*, and @tanstack/store package families are not part of this compromise. If you only depend on @tanstack/react-query and have no router/start dependency, you are very likely unaffected — but verify against your lockfile.

Critical: Revocation Order Matters

This is the single most important paragraph in this article. If you installed any compromised package and immediately rush to revoke your GitHub token, you may trigger the dead-man's switch and destroy your home directory.

The correct order is:

  1. Disconnect the affected machine from the network. Pull the cable. Turn off Wi-Fi. Do this first.
  2. If anything in your home directory matters and is not already backed up elsewhere, copy critical files to external media before any cleanup. Do not trust the running system.
  3. Identify and remove the persistent daemon (commands below) and confirm it is no longer running.
  4. Only after the daemon is dead, begin credential rotation in the priority order Socket recommends: npm tokens first, then GitHub PATs and OIDC trust relationships, then cloud credentials (AWS static keys and instance roles), then Vault tokens, then Kubernetes service account tokens.

Detection commands you can run before reconnecting:

# Look for persistence files (Linux + macOS)
find ~ -path '*/.claude/setup.mjs' -o -path '*/.vscode/setup.mjs' 2>/dev/null
find ~/.local/bin -name 'gh-token-monitor.sh' 2>/dev/null
find ~/.config/systemd/user -name 'gh-token-monitor.service' 2>/dev/null
ls ~/Library/LaunchAgents/com.user.gh-token-monitor.plist 2>/dev/null

# Look for the running daemon
ps aux | grep -E 'tanstack_runner|router_runtime|gh-token-monitor|bun'

# Remove the daemon (Linux)
systemctl --user stop gh-token-monitor.service
systemctl --user disable gh-token-monitor.service
rm ~/.config/systemd/user/gh-token-monitor.service
rm ~/.local/bin/gh-token-monitor.sh

# Remove the daemon (macOS)
launchctl unload ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
rm ~/Library/LaunchAgents/com.user.gh-token-monitor.plist

If you have already revoked tokens before reading this, check the integrity of your home directory immediately. If ~/ is empty or contents are missing, assume the destructive handler ran and restore from backup. If the directory looks intact, the daemon may not have executed yet — disconnect from the network and follow the steps above.

Why This Attack Matters for AI Developer Tooling

The MG editorial through-line has been consistent across every supply chain piece this year: when you do not control the infrastructure, you do not control the failure modes. Mini Shai-Hulud is the strongest evidence yet for that argument in the AI tooling context specifically.

Three things are happening at once. First, the AI dev tooling stack is maturing into a primary attack surface because it sits where the credentials are. LLM proxy libraries hold API keys for every model provider. Coding agents have permission to read your file system, run shell commands, and modify configuration. MCP server configurations describe every external service the agent can reach. These are exactly the kinds of high-value persistence and credential surfaces that attackers historically went after via more roundabout means.

Second, the legitimate features of legitimate tools are being repurposed as infection vectors. Claude Code's SessionStart hook exists so that teams can configure project-specific behavior when a session opens. VS Code's folderOpen task trigger exists so that contributors can have a workspace auto-configure. Neither feature is broken, and neither has a patch on the way that would actually fix this — because the feature is doing exactly what it was designed to do. The fix lives upstream, in how repositories are reviewed, how lockfiles are pinned, and how lifecycle scripts are gated.

Third, the cryptographic guarantees that the industry has been pointing at as the answer have been shown to be answering the wrong question. SLSA provenance answers "did the official pipeline produce this artifact?" It does not answer "was the pipeline run free of attacker-controlled code execution?" That second question, it turns out, is the one that matters.

The TeamPCP Campaign Trajectory

For readers who have followed MG's supply chain coverage, this is the same actor, the same toolchain family, and a continuation of a campaign that has been escalating since late February:

  • March 19, 2026 — Trivy. TeamPCP force-pushed malicious code to 76 of 77 trivy-action version tags, harvesting CI/CD secrets from any pipeline running Trivy that day. The downstream cascade reached Cisco's internal development environment, with 300+ private repositories cloned.
  • March 23–24, 2026 — Checkmarx KICS and LiteLLM. Credentials stolen from Trivy users fed compromises of Checkmarx's GitHub Actions and the LiteLLM PyPI package, covered in our LiteLLM supply chain attack analysis.
  • April 29, 2026 — SAP CAP. First documented use of Claude Code SessionStart and VS Code tasks.json as a persistence mechanism, in a smaller wave hitting four SAP-affiliated npm packages.
  • May 11, 2026 — Mini Shai-Hulud (current wave). SLSA provenance bypass, 170+ packages, AI tooling persistence at scale, the dead-man's switch.

A note on attribution: the axios npm supply chain attack covered in our March 31 piece is a separate operation. Microsoft and Google's Threat Intelligence Group attributed axios to UNC1069, a North Korean state-affiliated actor, not to TeamPCP. The two attacks coincided in timing but not in actor or method.

What to Do Right Now

  1. Scan your lockfiles for compromised packages. Snyk, Socket, and Semgrep have free scanners that will identify exposure. The community has also published detection scripts including omarpr/mini-shai-hulud-ioc-scanner — verify any scanner before running it. Rationale: most teams discover supply chain exposure through their lockfile, not through their direct dependency list, because malicious transitive dependencies are the entire point.
  2. If your lockfile is clean but you ran npm install after May 11 19:20 UTC, scan for IOCs anyway. Look for router_init.js, setup.mjs, router_runtime.js, or tanstack_runner.js at any package root in your node_modules. Rationale: registry-level cleanup happened fast, but you may have pulled a transient malicious version during the window.
  3. Check for persistence artifacts. Use the detection commands in the Revocation Order section above. Rationale: even if your direct dependencies were clean, an indirect install that pulled a poisoned package may have left the daemon behind.
  4. Kill the daemon before rotating any credentials. See the warning section above. Rationale: described in detail there. This step is the difference between losing your home directory and not.
  5. Audit recent commits on your own repositories for unexpected .claude/settings.json or .vscode/tasks.json additions, and any commit authored under claude@users.noreply.github.com that you did not make. Rationale: the worm uses stolen tokens to commit persistence files into your repositories under a fabricated author identity impersonating Anthropic's Claude GitHub App.
  6. Delete any GitHub repository on your account with the description string Shai-Hulud: Here We Go Again or A Mini Shai-Hulud has Appeared. Rationale: these are exfiltration repositories the worm created on your account with your stolen tokens. They contain encrypted bundles of your stolen credentials.
  7. Block the C2 infrastructure at your DNS or firewall: git-tanstack.com, *.getsession.org, api.masscan.cloud, and IP 83.142.209.194. Rationale: even if you have remediated, blocking these surfaces flushes out machines on your network that you may have missed.
  8. Going forward, default CI to npm install --ignore-scripts. Allow lifecycle scripts only for packages that genuinely need them. Consider pnpm v10 or Bun as your installer; both block lifecycle scripts by default. Pin exact versions in lockfiles. Add .claude/, .vscode/, and MCP configuration files to your standard PR review checklist. Rationale: this is the only structural defense that survives the next wave of this campaign, which is coming.

The Structural Problem: Lifecycle Scripts as Installed Attack Surface

npm packages can declare preinstall, prepare, and postinstall scripts that execute arbitrary code at install time — before any audit tool runs, before any code review, before the package is even fully resolved in the dependency tree. This is the delivery mechanism for every major npm supply chain attack since Shai-Hulud first emerged in September 2025, including this campaign, the SAP CAP wave, the Bitwarden CLI compromise, and the original Shai-Hulud worm.

The default behavior is a relic of a more trusting era. The ecosystem has now had four major supply chain waves in eight months. The assumption that you can trust arbitrary preinstall code from any package in your dependency tree, no matter how transitive, is no longer defensible. npm install --ignore-scripts should be the default for CI, and arguably for developer machines, with explicit allowlisting for the small number of packages that genuinely require lifecycle scripts to function. pnpm v10 and Bun-as-installer have already moved to this stance by default.

The Local-First Argument

Every supply chain attack we have covered this year tells the same story in different vocabulary. The LiteLLM piece was about an LLM gateway holding every model provider's API keys. The Cisco/Trivy piece was about a vulnerability scanner inheriting the privileges of every CI/CD pipeline that ran it. The axios piece was about an HTTP client present in 80% of cloud and code environments. Mini Shai-Hulud is about the legitimate publishing pipeline of a foundational React ecosystem package being hijacked to publish cryptographically-signed malware.

The shared structural problem: every dependency you do not control is a credential rotation, a code review, and a release pipeline you are trusting someone else to get right. Each of those trust assumptions has now failed in production at scale.

Practical mitigation for home-lab and local AI builders looking at this campaign and worrying about their stack: keep developer machines on a separate network segment from your local AI inference hosts, your NAS, and your home network infrastructure. Run AI inference servers with no outbound internet permission past the initial model download — Ollama on a dedicated host inside a VLAN with a default-deny egress rule eliminates entire categories of this risk. Prefer dependencies with minimal transitive trees, and prefer Python or Go projects over npm ones where the choice exists, given the lifecycle script delivery mechanism that has powered every Shai-Hulud wave. None of this is bulletproof. It is risk reduction, not risk elimination. But it caps the blast radius of the next compromise, which is the realistic goal.

Frequently Asked Questions

Did npm audit signatures catch this attack?

No. The attacker used the legitimate TanStack OIDC publishing identity, so the SLSA Build Level 3 attestations are real and cryptographically valid. This is the property that makes this campaign genuinely novel — provenance verification cannot detect it. Source code review against the upstream repository, or behavioral monitoring of install-time scripts, is the only reliable detection path.

Is Claude Code itself compromised?

No. The @anthropic-ai/claude-code package is not on any affected list. The attack abuses Claude Code's SessionStart hook feature as a persistence mechanism inside compromised third-party repositories. The malicious .claude/settings.json file is committed by the worm into other projects, not into Claude Code itself. Anthropic flagged the SessionStart attack surface in its own issue tracker roughly two weeks before this campaign began.

I already revoked my GitHub token. What do I do now?

Check the integrity of your home directory immediately. If ~/ appears empty or substantially missing, the destructive handler likely ran — restore from backup, treat the machine as fully compromised, and reinstall the operating system before reuse. If the directory looks intact, the daemon may not have executed yet (it polls every 60 seconds, so the trigger is fast but not instant); disconnect from the network and run the daemon removal commands above before doing anything else.

I use yarn, pnpm, or Bun instead of npm. Am I protected?

Yarn still executes lifecycle scripts by default and is exposed the same way. pnpm v10 and Bun block lifecycle scripts by default unless explicitly allowed — these are meaningfully safer choices, not bulletproof ones. The worm propagation mechanism varies by wave; in the TanStack cluster, the trigger is a prepare lifecycle hook executed via Bun, which means even Bun users who allowed the script via a transitive dependency could be affected. Pinning exact versions and reviewing package.json changes in PRs remains the strongest defense regardless of package manager.

Why does the malware exit on Russian-language systems?

The malware checks the system locale and exits cleanly if the value is ru. This is a longstanding CIS-exemption pattern among Russian and Russia-adjacent threat actors, used to reduce risk of prosecution under Russian computer crime law. Combined with the Israel/Iran geofenced destructive branch documented by Microsoft, the locale logic is consistent with an operator based in Russia or a CIS-aligned state.

Does this affect home users running n8n, Home Assistant, or local AI tooling?

It can, indirectly. Most home-lab AI stacks do not depend on TanStack, Mistral AI's official client, or Guardrails AI directly. But many custom Home Assistant integrations, Node-RED flows, n8n workflows, and MCP server configurations use Node.js packages, and any of those that ran npm install on or after May 11 19:20 UTC could have pulled a poisoned transitive dependency. Check your lockfiles. If your local AI inference server has no developer tooling on it (no npm, no GitHub tokens, no SSH keys to external services) and no outbound internet access past model downloads, your exposure on that specific host is minimal regardless.

Is this campaign over?

No. TeamPCP has now demonstrated end-to-end automation of credential theft, OIDC token hijacking, SLSA-attested malicious publishing, AI-agent persistence, and self-propagation across both npm and PyPI. Each wave of this campaign has built on the previous wave's tradecraft. Expect additional ecosystems (RubyGems, crates.io, Maven Central) to be plausible next targets, and expect future waves to combine the techniques demonstrated here into harder-to-detect compromises. The structural defenses described above — lifecycle script gating, exact version pinning, configuration file review — are the realistic mitigation path.

USA-Based Modem & Router Technical Support Expert

Our entirely USA-based team of technicians each have over a decade of experience in assisting with installing modems and routers. We are so excited that you chose us to help you stop paying equipment rental fees to the mega-corporations that supply us with internet service.

Updated on

Leave a comment

Please note, comments need to be approved before they are published.