Mini Shai-Hulud: When SLSA-Signed Packages Carry Malware
On May 11, 2026, between roughly 19:20 and 19:26 UTC, an attacker tracked as TeamPCP published 84 malicious versions across 42 @tanstack/* npm packages (GitLab Advisory Database). The publishes were authenticated through TanStack’s legitimate GitHub Actions OIDC trusted-publisher binding — meaning every tarball shipped with valid Sigstore attestations and SLSA Build Level 3 provenance that pointed back to the real TanStack/router Release workflow (BleepingComputer). The incident is tracked as CVE-2026-45321 with a CVSS score of 9.6 (Critical).
This is the supply-chain failure mode every CISO has been warned about: a worm that doesn’t need to steal a long-lived publish token because it borrows the build pipeline’s identity instead. If your developers installed any affected package in the past 36 hours, treat their workstations and CI runners as compromised until proven otherwise.
What’s in scope
The campaign — researchers are calling it Mini Shai-Hulud, after the September 2025 worm of the same family — has reached an estimated 170+ packages across npm and PyPI with more than 518 million cumulative downloads, and created roughly 400 attacker-owned GitHub repositories tagged with the string Shai-Hulud: Here We Go Again (The Hacker News).
Confirmed compromises so far include:
- TanStack — 42
@tanstack/*npm packages, 84 versions (CVE-2026-45321) - Mistral AI —
mistralai@2.4.6(PyPI) - Guardrails AI —
guardrails-ai@0.10.1(PyPI) - OpenSearch Project —
@opensearch-project/opensearch@3.5.3, 3.6.2, 3.7.0, 3.8.0 - UiPath, DraftLab, and several other maintainers’ packages including
@squawk/*and@tallyui/*
Counts vary across vendors because each is measuring at a different snapshot: Endor Labs reports 160+ npm packages, Aikido logged 373 malicious package-version entries, and Socket has tracked 416 compromised artifacts across npm and PyPI.
How the attack worked
TanStack’s post-mortem describes a three-stage chain against their own GitHub Actions environment — none of which required stealing an npm token:
pull_request_targetabuse. A risky workflow trigger ran with elevated permissions against attacker-controlled code in a fork.- GitHub Actions cache poisoning. The attacker planted artifacts that subsequent legitimate runs trusted.
- OIDC token extraction from runner memory. With code execution inside a privileged job, the attacker read the GitHub Actions OIDC token directly out of the runner process.
That OIDC token is the prize. Because TanStack’s npm trusted publisher binding was scoped at the repository level — not pinned to a specific protected branch and workflow file — the attacker could request a valid short-lived npm publish token from the legitimate Release workflow surface and push tarballs that npm’s signing infrastructure then attested as authentic.
The delivery trick is also worth flagging: the attackers staged the payload on an orphaned commit in a fork of TanStack/router. Because GitHub’s fork network shares object storage, the commit was reachable by SHA even though no branch pointed at it. The published tarball declared an optionalDependency against that commit, and the dependency’s prepare lifecycle hook executed the payload via the Bun runtime on install. The Mistral AI PyPI packages used the older Shai-Hulud pattern — a preinstall hook in package.json invoking node setup.mjs to download Bun and run the same payload.
What the malware does
Once it executes, the credential stealer is wide-ranging:
- Targets harvested: GitHub Actions OIDC tokens and PATs, Git credentials, npm publish tokens, AWS Secrets Manager / IAM / ECS task credentials, Kubernetes service-account tokens and kubeconfigs, HashiCorp Vault tokens, SSH keys,
.envfiles, cryptocurrency wallet data, Claude Code configs, and VS Code task definitions. - Persistence: installs hooks in Claude Code and VS Code so the stealer re-runs on every IDE launch, and a
gh-token-monitorservice that re-exfiltrates fresh GitHub tokens over time. - CI hijack: drops two malicious GitHub Actions workflows that serialize repository secrets into JSON and POST them to
api.masscan[.]cloud. - Exfiltration: primary channel is
filev2.getsession[.]orgover Session Protocol — chosen because few enterprises block decentralized messaging infrastructure. Fallback channel is a Git push to attacker-owned repos under the spoofed authorclaude@users.noreply.github.comvia the GitHub GraphQL API. - Worm logic: if a stolen npm token has
bypass_2fa=true, the malware enumerates every package the maintainer publishes and uses GitHub OIDC exchanges to mint per-package publish tokens, sidestepping authentication entirely. - Destructive branch: Microsoft’s analysis of the Mistral AI PyPI package found country-aware logic that avoids Russian-language environments and a 1-in-6 chance of executing
rm -rf /when the host looks Israeli or Iranian.
This is the first documented case of a worm shipping validly attested malicious packages. The provenance check passed because the build infrastructure itself was the attacker’s signing oracle.
ATT&CK mapping
- T1195.002 — Supply Chain Compromise: Compromise Software Supply Chain
- T1078.004 — Valid Accounts: Cloud Accounts (OIDC token abuse)
- T1552.004 — Unsecured Credentials: Private Keys / Tokens
- T1567 — Exfiltration Over Web Service (Session Protocol, GitHub GraphQL)
- T1546 — Event-Triggered Execution (IDE persistence)
- T1059.007 — Command and Scripting Interpreter: JavaScript (Bun runtime)
Indicators to block and hunt
Block at egress proxy or DNS:
filev2.getsession[.]org(and any*.getsession.orgnot required for business use)api.masscan[.]cloudgit-tanstack[.]com83.142.209[.]194
Hunt across endpoints and CI:
- Files named
router_init.js,router_runtime.js, orsetup.mjsappearing undernode_modulesafter install - New GitHub commits authored as
claude@users.noreply.github.comin repositories you own - Newly created repositories on developer accounts containing the string
Shai-Hulud: Here We Go Again - Unexpected
gh-token-monitorservices or scheduled tasks on developer workstations - Outbound traffic to Session Protocol relays from build runners (rarely legitimate)
- New GitHub Actions workflow files added outside change-control windows, particularly any that read
secrets.*and post to external hosts
Cyberuptive’s SOC has pushed correlation rules for these patterns into the Trellix Helix and OpenSearch detection content we maintain for managed customers. Reach out if you’d like the Sigma equivalents ported to your stack.
What to do this week
In priority order:
- Inventory and quarantine. Run
npm ls @tanstack/...andpip show mistralai guardrails-aiacross developer workstations, CI runners, and container images. Compare installed versions to the public IoC lists from Socket, Endor Labs, and StepSecurity. Quarantine any affected hosts. - Assume credential exposure. Rotate GitHub PATs, GitHub App private keys, npm tokens, AWS access keys, Vault tokens, Kubernetes service-account tokens, SSH keys, and any
.envsecrets reachable from affected workstations or runners. Treat OIDC trust relationships from the same repos as suspect and re-pin them. - Lock down your own trusted-publishing configs. In npm and PyPI, pin trusted publishers to a specific branch and workflow file, not the whole repository. Disable
pull_request_targettriggers anywhere they aren’t strictly required, and never let untrusted forks reach jobs withid-token: writeor access to release secrets. - Harden GitHub Actions. Enforce minimum permissions (
permissions: read-allas default, write only where needed), require manual approval for first-time contributors, disable cache reuse across forks, and route runners through allow-listed egress. - Audit IDE persistence. Inspect Claude Code and VS Code config directories on developer endpoints for unfamiliar startup tasks or extensions added in the last 72 hours.
- Block IoCs. Push the domains and IP above into web proxies, DNS firewalls, and EDR custom indicators today.
- Tabletop the SLSA-attested-malware scenario. Provenance is necessary but not sufficient. Update your supply-chain runbook to require time-based holds (e.g., 24–72 hours) before promoting newly published versions of critical dependencies, regardless of attestation status.
What this changes
For the last two years, the industry has sold trusted publishing and SLSA provenance as the answer to supply-chain attacks. They are still the right direction — long-lived NPM_TOKEN secrets in CI are worse — but Mini Shai-Hulud proves that provenance attests where the build happened, not whether the build is honest. If the pipeline is compromised, the signature is, too.
For CISOs, the practical implication is that signed-package gates need to be paired with behavioral controls on the build environment: scoped OIDC bindings, branch- and workflow-pinned trust, runner egress allow-listing, and detection content that watches for OIDC-token theft patterns. For practitioners, the takeaway is that npm install --ignore-scripts and pinned lockfiles just became baseline hygiene, not a power-user optimization.
For our defense-industrial-base customers under CMMC, this incident maps cleanly to SI.L2-3.14.2 (malicious code protection), CM.L2-3.4.6 (least functionality), AC.L2-3.1.5 (least privilege), and CA.L2-3.12.4 (system security plan). Expect assessors to start asking how you’d detect a SLSA-attested malicious package in your build chain. If your answer is “we trust the signature,” it’s time to revisit your SSP.
Cyberuptive runs a 24/7 follow-the-sun SOC staffed by U.S.-based analysts, headquartered in Honolulu and serving customers across Asia-Pacific and the U.S. mainland. We help mid-market organizations, MSPs, and Pacific defense subcontractors close the gaps adversaries — human and machine — are looking for.
Talk to us about a no-obligation supply-chain risk review, or read our SOC-as-a-Service overview.