SLSA • Mini Shai-Hulud: Where SLSA's Boundaries Fall
by Andrew McNamara (Red Hat)
15 May 2026
On May 11, 2026, attackers compromised 84 npm package artifacts across 42 @tanstack packages, and the worm spread to 170+ packages across @mistralai, @uipath, and other namespaces. The “Mini Shai-Hulud” attack chained a GitHub Actions workflow misconfiguration, cache poisoning, and OIDC token extraction to publish malicious packages through legitimate CI/CD pipelines.
Several reports described these packages as carrying “valid SLSA Build Level 3 attestations.” The attestations were cryptographically valid: the attacker extracted the legitimate OIDC token from runner memory and signed through Sigstore, producing attestations indistinguishable from the real thing. But the build platform that generated them did not meet SLSA Build L3 isolation requirements, and a platform that did would have prevented this specific attack vector. A signed artifact is not necessarily a trustworthy one. Some gaps SLSA cannot close on its own are addressable by layering policy on top; others require different controls entirely. This post maps where those boundaries fall.
What happened
The attack exploited three weaknesses in sequence.1
Pwn Request: TanStack’s bundle-size.yml workflow used the pull_request_target trigger, which runs fork-contributed code in the base repository’s security context. The attacker opened a pull request from a fork and executed malicious code within the trusted repository.
Cache poisoning: The malicious code poisoned the pnpm package store under the cache key that the legitimate release.yml workflow would later restore. GitHub Actions shares cache scope across trigger types, so the release workflow consumed the poisoned cache unknowingly.
OIDC token extraction: When the release workflow ran with id-token: write permission, attacker-controlled code from the poisoned cache scraped the runner process memory, extracted the ambient OIDC token, and published directly to npm, bypassing the workflow’s conditional publish logic entirely.
The result: 84 malicious packages published under the legitimate TanStack identity, carrying npm provenance attestations that pointed to the correct repository, workflow, and ref.
Did valid SLSA provenance protect against these exploits?
No. Understanding why matters.
The compromised packages carried cryptographically valid attestations: the attacker used the legitimate OIDC token, extracted from runner memory mid-workflow, to authenticate to Sigstore’s Fulcio CA and sign through npm’s trusted publishing infrastructure. The resulting attestations accurately reported the builder (github.com/actions/runner/github-hosted), the repository (TanStack/router), and the workflow (release.yml@refs/heads/main). They were indistinguishable from attestations on legitimate packages.
The issue is not the attestations; it is the build platform behind them. The attestations are a record of what the build platform observed. When attacker-controlled code runs inside that platform, the observations are accurate but the build was compromised. SLSA Build L3 addresses this by requiring that the build platform guarantee isolation: no external influence can alter the build except through declared parameters. Specifically:
It MUST NOT be possible for one build to inject false entries into a build cache used by another build, also known as “cache poisoning.”
It MUST NOT be possible for a build to access any secrets of the build platform, such as the provenance signing key.
It MUST NOT be possible for one build to persist or influence the build environment of a subsequent build.
The TanStack attack violated all three properties. A prior workflow run poisoned the cache; the build exposed the OIDC signing identity; and the attacker’s code persisted through the shared cache. A build system meeting SLSA Build L3 requirements would have prevented the cache poisoning vector that enabled this attack.
npm’s built-in provenance achieves Build L2: the build runs on a hosted platform and provenance is authenticated. That is a real and meaningful guarantee. L2 provenance binds a package to its canonical source repository and build system, which is why it protects effectively against dependency confusion attacks where an attacker registers an impostor package but cannot produce provenance from the legitimate source. What L2 does not require is isolation. The build platform need not guarantee that builds cannot influence one another, or that signing credentials are inaccessible to the build steps. Those are L3 requirements, and the TanStack attack exploited exactly that gap. To protect against this class of attack, use a builder that enforces cache isolation between builds at the platform level and keeps the signing identity structurally inaccessible to the build process.
What SLSA can help with
SLSA provenance lets consumers verify that a specific builder from a specific source repository produced a...