PERMISSION/PROTOCOL
Back to incident tracker

2026-05-11

CriticalPrimary

Mini Shai-Hulud supply chain worm compromises TanStack, Mistral AI, and 170+ npm/PyPI packages via GitHub Actions cache poisoning

TeamPCP's Mini Shai-Hulud worm compromised 170+ npm/PyPI packages including TanStack and Mistral AI via GitHub Actions cache poisoning, stealing CI credentials and persisting via Claude Code hooks.

npm / TanStack / Mistral AI / Guardrails AICredential exposurenpm supply chain compromise / CI credential theftnpm registry / PyPI / GitHub Actions runners / Developer workstations / Claude Code

What happened

Attacker submitted a malicious PR fork, poisoned GitHub Actions runner cache across fork-trust boundary, extracted OIDC token from runner memory, and published 84 malicious package versions using TanStack's legitimate publishing identity. Payload then stole CI credentials and wrote itself into Claude Code hooks for workstation persistence.

Why it matters

Any developer or CI environment that ran npm install against an affected @tanstack/* version on May 11 should be considered compromised. Credentials exposed include GitHub PATs and OIDC trusts, AWS IAM keys, HashiCorp Vault tokens, and Kubernetes service account tokens. A dead-man's switch wipes the local disk if a stolen GitHub token is revoked.

Missing authorization check

GitHub Actions OIDC trusted-publisher bindings require an explicit human-signed receipt before npm publish — attacker code that executes in the runner mid-workflow should not be able to publish under the maintainer's identity. Claude Code hook configuration modifications should also require an explicit authorization receipt.

Would PP block it?

The supply chain compromise itself (CI cache poisoning, OIDC token extraction) is outside PP's enforcement surface. Post-compromise, if agent tooling routes cloud credential access through PP, the Credential Gate would surface unauthorized access patterns. The Claude Code hook persistence vector is directly addressable: PP can require a signed receipt before any modification to .claude/settings.json hook configuration, preventing the worm from establishing persistent re-execution on developer workstations.

Incident analysis

Timeline and technical read

Timeline

  1. 2026-05-11

    19:20–19:26 UTC: attacker publishes 84 malicious @tanstack/* versions using TanStack's legitimate OIDC identity after GitHub Actions cache poisoning.

  2. 2026-05-11

    19:56 UTC: StepSecurity detects and reports the compromise within 30 minutes; Socket AI Scanner flagged all packages in under 6 minutes of publication.

  3. 2026-05-11

    21:30 UTC: GitHub publishes security advisory GHSA-g7cv-rxg3-hmpx. TanStack deprecates affected versions and engages npm security to remove malicious tarballs.

  4. 2026-05-12

    Campaign expands: Socket confirms additional compromised artifacts in Mistral AI, Guardrails AI, OpenSearch, UiPath, and Squawk packages across npm and PyPI.

  5. 2026-05-12

    TanStack founder Tanner Linsley publishes postmortem; Mistral AI project quarantined on PyPI. Campaign attributed to TeamPCP threat group.

Technical breakdown

  • GitHub Actions cache poisoning via pull_request_target 'Pwn Request' pattern allowed attacker-controlled code to run in the base repository's trusted context, extracting the OIDC token from runner memory — same technique used in the tj-actions compromise of 2025.
  • This is the first documented case of a malicious npm package carrying valid SLSA provenance: the worm hijacked the legitimate CI pipeline itself, so Sigstore correctly attested the build process while remaining blind to the malicious payload within it.
  • The payload writes itself into Claude Code's .claude/settings.json hooks, ensuring re-execution every time a developer uses Claude Code in the affected directory — npm uninstall alone is insufficient remediation.
  • A dead-man's switch installs a system user service that monitors whether the stolen GitHub token has been revoked; if revoked, it triggers a complete local disk wipe, weaponizing incident response against victims.
  • Credential harvest targets GitHub Actions env vars, AWS IMDS and Secrets Manager, HashiCorp Vault, Kubernetes service accounts, SSH keys, crypto wallets, VPN configs, and shell history — 100+ hardcoded credential paths across platforms.

Authorization boundary

Where the authorization boundary should have been

This incident is categorized as Credential exposure. The relevant Permission Protocol gate is Credential Gate. The read is conditional: the block only applies where the real action boundary is routed through a gate.

If enforced at
GitHub Actions OIDC publish authorization / Claude Code hook configuration writes / CI credential access
Still needs
Supply chain integrity at npm install time; runner-level code execution prevention; SLSA provenance verification of build-time code safety (not just build process)
Receipt required for
npm publish using OIDC trusted-publisher identity; modification of Claude Code hook configuration; access to CI/cloud credentials from GitHub Actions runner

PP governs agent action authorization, not npm install-time payload execution. However, PP's Credential Gate would limit blast radius post-compromise by requiring a signed receipt for cloud credential use, and PP's hook-write authorization could block the Claude Code persistence mechanism.

Start small

Put the relevant gate at this action boundary.

This incident maps to Credential Gate. Start with the boundary that controls the actual action, then require a signed receipt before execution.

Replay this incident with a signer in the loop