The Signatures Were Valid. That's the Problem.
The Signatures Were Valid. That's the Problem.
TanStack's packages were compromised. The malicious versions carried valid SLSA provenance — issued by GitHub's OIDC infrastructure, referencing the real TanStack repository, built by the official release pipeline.
Every verification check passed. Because technically, none of them were wrong.
The attacker didn't steal credentials. They didn't compromise a tool. They poisoned the release pipeline itself and let it do the signing.
Why This Is Different
Every supply chain attack over the past two months had a clear failure point you could name. A stolen token. A misconfigured workflow. A compromised dependency.
This one doesn't.
Previous attacks needed something external — a phished maintainer, leaked credentials, a known misconfiguration. TanStack required none of that. The attack ran through the legitimate publishing pipeline, in the correct repository, on the correct branch. The packages look right because the pipeline that built them was real. The provenance is accurate because it was generated by GitHub's own OIDC infrastructure.
There was nothing to detect, because nothing was technically wrong — until you look at what the pipeline was actually running.
Signed packages are no longer a sufficient trust signal when the build system itself is the attack surface.
The Pattern, So Far
In March, the axios RAT worked by stealing the lead maintainer's npm credentials and using them to publish a malicious version. The attack surface was the human — compromise the person, compromise the package.
In the Trivy chain, the attacker didn't need the human. They exploited a misconfigured GitHub Actions workflow, stole a privileged access token, and moved laterally across CI/CD pipelines — including Cisco's. The attack surface shifted from the person to the toolchain.
TanStack moved it again — to the pipeline itself.
| Attack | What was compromised | What the attacker used |
|---|---|---|
| Axios RAT (March 2026) | Maintainer credentials | Stolen npm token |
| Trivy / Cisco (March 2026) | Security tooling | Misconfigured GitHub Actions token |
| TanStack (May 2026) | Release pipeline | Legitimate OIDC + SLSA provenance |
Each attack moved one layer closer to the root of trust. Axios needed a human to compromise. Trivy needed a misconfigured workflow. TanStack needed neither — just the gap between how pull_request_target is documented and how most repositories actually configure it.
What Actually Happened
The TanStack postmortem is specific about the mechanism. Three GitHub Actions primitives, chained together. The key thing before reading this: the attack worked because GitHub Actions treated untrusted code as trusted long before the release step ever started.
pull_request_target
This workflow trigger runs in the context of the base branch — not the fork. That distinction matters enormously. A normal pull_request trigger runs in the fork's context and has no access to repository secrets. pull_request_target runs with the base branch's full permissions — which includes secrets, OIDC token minting, and deployment environments.
When a repository checks out fork code inside a pull_request_target workflow and then runs it, any code the fork introduces executes with access to everything the base branch can access. Most public repositories have this misconfigured. TanStack wasn't uniquely careless.
At that point, the attacker no longer needs stolen credentials. The workflow itself becomes the credential.
Cache poisoning
GitHub Actions caches are keyed by branch and scope, but the isolation between trusted and untrusted workflow runs is weaker than most people assume. An attacker-controlled workflow can write entries to a cache that a subsequent legitimate workflow will restore. The poisoned cache gets loaded into the release pipeline. From that point, it executes in a fully trusted context with no record of the contamination.
This is what bridges the gap between "attacker has access to a workflow run" and "attacker has access to the release pipeline." The cache is the hand-off point, and it doesn't come with a warning label.
OIDC token minting from the compromised runner
Modern trusted publishing — on npm, PyPI, and most cloud providers — works through GitHub's OIDC tokens. The idea is that you don't store long-lived secrets at all. Instead, the runner requests a short-lived token from GitHub's identity service, and npm accepts it as proof that this workflow, in this repository, on this branch, is who it claims to be.
The problem is that OIDC tokens are minted from the runner. If the runner is compromised — which it was, via the poisoned cache — the token it mints is completely legitimate. GitHub's identity service issues it. npm verifies it. The package is published under the TanStack identity.
The SLSA provenance artifact that gets attached to the package says: built in the TanStack repository, on the main branch, by the official release workflow. All of that is technically true. The pipeline was the TanStack pipeline. It was just running an attacker's payload.
pull_request_target trigger
↓
Fork code checked out in base branch context
↓
Poisoned cache entry written during untrusted run
↓
Cache restored in legitimate release workflow
↓
Attacker code executes with base branch permissions
↓
OIDC token minted from compromised runner
↓
Malicious package published to npm
↓
Valid SLSA provenance attached
↓
Every verification check passes
TanStack Is One Node in a Larger Campaign
The compromise is being tracked as part of a coordinated campaign called Mini Shai-Hulud, hitting npm and PyPI simultaneously. I'll be honest — when I first read through the postmortem, I expected a story about a stolen token. This is a different category of attack.
Other confirmed packages: Mistral AI SDKs, UiPath packages, the OpenSearch JS client, Guardrails AI packages. The scope is wider than any single maintainer or ecosystem.
The malware behavior compounds the problem significantly. Once installed, it harvests credentials — GitHub tokens, cloud credentials, SSH keys, npm tokens, CI secrets — and then enumerates other packages the compromised maintainer owns. It republishes poisoned versions of those packages automatically.
A single compromised release pipeline becomes a propagation node across everything that maintainer touches. The initial compromise scales horizontally without additional attacker effort.
The Trust Model Is Collapsing One Layer at a Time
The industry built a layered verification model over the past several years: trusted publishers, signed packages, SLSA provenance, reproducible builds. Each layer was a response to a previous attack. Credential theft led to trusted publishing. Unsigned packages led to provenance. The assumption was that enough layers eventually constituted a trustworthy chain.
TanStack didn't break a layer. It demonstrated that if you control the pipeline, all of the layers sign your output.
The vibe coding post made the same case from a different direction — the AI produces what it was asked for, and security is everything the question didn't cover. Supply chain attacks follow an identical structural pattern. The verification system validates what it's told to validate. It has no concept of whether the pipeline feeding it was clean.
AI Is Already Part of This
The techniques here — pull_request_target abuse, cache poisoning, OIDC trust exploitation — are documented individually. Security researchers have written about each of them. They've appeared in CVEs. None of this is novel.
What's changing is the cost of chaining them.
Finding a misconfigured pull_request_target workflow across thousands of public repositories used to require manual review. Understanding which repositories have release pipelines worth targeting required ecosystem knowledge. Constructing a cache poisoning chain that survives into a trusted run required familiarity with GitHub Actions internals.
A current-generation model with scripting around it can do all of that at scale. Scan workflow files across GitHub. Flag repositories where pull_request_target checks out fork code. Map which ones have npm publish steps with id-token: write. Enumerate the maintainer's other packages. The output is a prioritized target list, not a research exercise.
The attackers running Mini Shai-Hulud do not need a frontier model. They need whatever is available to everyone, pointed at GitHub Actions YAML files.
What's Happening Now
npm has pulled the compromised versions. The known C2 infrastructure is offline.
If you use any of the affected packages — TanStack Query, TanStack Router, TanStack Form, or any package in the Mistral, UiPath, OpenSearch, or Guardrails AI ecosystems — check your lockfile:
# Check for known malicious versions
npm list --all 2>/dev/null | grep -E "tanstack|mistral|guardrails"
Check for any suspicious postinstall artifacts
grep -r "plain-crypto" node_modules/.package-lock.json 2>/dev/null
If you were in the exposure window, rotate everything accessible from that machine or CI environment. The malware's first action is credential enumeration, not immediate exfiltration — the same pattern as the axios RAT, the same pattern as Cloud Stealer from the Trivy chain. It catalogs before it acts.
Treat everything as compromised until you've confirmed the lockfile state before the attack window.
The Open Question
The security industry's response to credential theft was trusted publishing. The response to unsigned packages was SLSA provenance. Both of those controls are now demonstrably insufficient when the pipeline itself is the attack surface.
The hard question isn't what to patch. It's whether the current model — where release pipelines are ephemeral, runners are trusted implicitly, and provenance is generated at build time — can be made secure at all without changing its fundamental architecture.
Cache isolation, scoped OIDC trust, restricted pull_request_target usage — these help at the margins. But they're configuration changes on top of a system that was designed for velocity, not adversarial conditions.
The Trivy post ended with: the attack surface is the entire trusted toolchain, and that's a harder problem than any checklist solves.
TanStack suggests it's harder still. The trusted toolchain is now generating signatures for its own compromise, and the signatures check out.
Related: Claude Leak → Axios RAT: The Supply Chain Story Nobody Connected
Related: Cisco Got Breached. They Ran a Security Scanner.
Related: Vibe Coding Is Shipping. AI Is Finding Zero-Days. Your App Is in the Middle.
#npm#Supply Chain Attack#GitHub Actions#TanStack#CI/CD#Security
Written by Vishwam Dhavale
Full stack developer building scalable web & mobile systems. Founding Engineer with a passion for clean architecture and great DX.
Related Articles
Cisco Got Breached. They Ran a Security Scanner.
Cisco didn't get phished. They didn't misconfigure a server. They ran Trivy — a vulnerability scanner — and that was enough. Here's the 12-day chain that nobody connected until it was too late.
Vibe Coding Is Shipping. AI Is Finding Zero-Days. Your App Is in the Middle.
AI can now assist in systematically uncovering zero-day vulnerabilities across every major OS and browser. Vibe coders are shipping production apps without knowing what SQL injection means. Here's the structural gap nobody is talking about.
Claude Leak → Axios RAT: The Supply Chain Story Nobody Connected
On March 31, 2026, Anthropic leaked 512,000 lines of Claude Code source. The same day, a North Korean RAT hit axios — the package Claude Code depends on.