Threat Intelligence2026-05-179 min read

Mini Shai-Hulud: The TanStack Supply Chain Attack That Hit OpenAI, Mistral, and 160+ Packages

A self-propagating supply chain worm compromised TanStack npm packages through GitHub Actions cache poisoning. No credentials stolen, just OIDC tokens extracted from runner memory.

What Happened

On May 11, 2026, a threat actor group called TeamPCP launched a coordinated supply chain attack dubbed "Mini Shai-Hulud" targeting the npm and PyPI ecosystems. The attack compromised 84 npm package artifacts across 42 @tanstack/* packages, along with packages from @mistralai/, @squawk/, and others. Over 160 packages total. @tanstack/react-router alone receives over 12.7 million weekly downloads.

OpenAI confirmed that two employee devices in their corporate environment were impacted, though they found no evidence of user data access, production system compromise, or software alteration.

The Attack Chain

The technical sophistication here is what makes this notable. The attacker did not steal npm credentials. Instead, they exploited a chain of three weaknesses in GitHub Actions:

  1. Fork and disguise: The attacker forked TanStack/router and renamed it to zblgg/configuration to evade fork-list monitoring.

  2. Cache poisoning via pull_request_target: They opened a PR that triggered a pull_request_target workflow. A known dangerous pattern where the workflow runs with the base repo's secrets but checks out the attacker's fork code. The malicious code poisoned the GitHub Actions cache with a compromised pnpm store.

  3. OIDC token extraction from /proc: When legitimate maintainer PRs merged to main and triggered release workflows, the poisoned cache was restored. Attacker-controlled binaries then extracted OIDC tokens directly from the GitHub Actions runner process memory (/proc/pid/mem). These tokens were used to publish malicious package versions. No npm credentials ever needed.

The CWE Relevance

CWE-829 (Inclusion of Functionality from Untrusted Control Sphere): The pull_request_target trigger grants repository-level secrets to code from external forks. This is CWE-829 in CI/CD form.

CWE-502 (Deserialization of Untrusted Data): Cache restoration is implicit deserialization. The pnpm store cache was treated as trusted without integrity verification.

CWE-922 (Insecure Storage of Sensitive Information): OIDC tokens accessible in /proc/pid/mem on shared runners represents sensitive credential exposure in a multi-tenant environment.

What Your Codebase Should Do

  1. Pin dependencies by hash, not just version. npm package-lock.json integrity fields exist for this reason. Verify them in CI.
  2. Audit pull_request_target workflows. If your workflow checks out PR code and runs it, you are vulnerable to this exact attack pattern. Use pull_request instead, or isolate the checkout.
  3. Monitor for unexpected package publishes. Socket, Snyk, and Wiz all flagged the malicious versions within hours. Automated dependency monitoring is no longer optional.

How Deva Detects This

Deva SCA (Software Composition Analysis) pipeline checks package integrity hashes against the lock file and flags version changes that do not match expected publication patterns. The supply chain preset surfaces CWE-829 and CWE-506 (Embedded Malicious Code) findings when dependency metadata indicates unsigned or unexpected publishers.

PostShare

Summer Ann

Threat research, application security analysis, and defensive engineering insights from the DevSecCode team.

Related Articles

Discussion

Loading comments...