TanStack Supply-Chain Attack Hit 42 npm Packages via GitHub Actions Exploit

5 min read 1 source breaking
├── "Trusted Publishing is necessary but insufficient — it shifts the trust perimeter without eliminating it"
│  ├── TanStack Team (TanStack Blog) → read

The postmortem details how the attacker exploited OIDC token extraction from runner memory to authenticate as the legitimate publisher, despite Trusted Publishing being in place. The attack demonstrates that TP eliminates long-lived credentials but cannot protect against code execution within the CI pipeline itself.

│  └── top10.dev editorial (top10.dev) → read below

The editorial argues that Trusted Publishing merely shifts trust from 'who has the token' to 'who controls the CI pipeline,' and that cache poisoning across the fork-to-base boundary rendered this distinction moot. The attack manufactured legitimate credentials rather than stealing them, exposing a fundamental architectural gap.

├── "The pull_request_target workflow is a systemic footgun that the ecosystem has failed to address despite years of warnings"
│  └── TanStack Team (TanStack Blog) → read

The postmortem identifies pull_request_target as the entry point — a well-documented but widely misunderstood GitHub Actions trigger that runs in the base repository's context, not the fork's. Despite being a known risk vector, it remains broadly used across major open-source projects.

├── "This was an automated, self-propagating worm — not a targeted attack on TanStack alone"
│  └── @varunsharma07 (Hacker News, 821 pts)

Confirmed that @mistralai/mistralai's npm package was compromised by the same worm mechanism, indicating automated propagation across the npm ecosystem rather than a manually targeted campaign against TanStack specifically. Mistral's package was subsequently pulled from the registry.

└── "The attack represents a new sophistication level in supply-chain compromise techniques"
  └── top10.dev editorial (top10.dev) → read below

The editorial characterizes this as 'one of the most technically sophisticated npm supply-chain attacks to date,' emphasizing the multi-stage chain: fork-based cache poisoning across trust boundaries, OIDC token extraction from runner memory, and legitimate credential manufacturing — all without needing stolen passwords or leaked tokens.

What happened

On May 11, 2026, an attacker executed one of the most technically sophisticated npm supply-chain attacks to date, compromising 42 @tanstack/* packages and publishing 84 malicious versions to the npm registry. The attack chain was a masterclass in exploiting the trust boundaries between GitHub's fork model, Actions CI infrastructure, and npm's publishing pipeline.

The entry point was a `pull_request_target` workflow — a well-documented but still widely misunderstood GitHub Actions trigger that runs in the context of the *base* repository, not the fork. The attacker submitted a pull request from a fork that poisoned the GitHub Actions cache across the fork-to-base trust boundary, then extracted OIDC tokens directly from runner memory to authenticate as the legitimate package publisher. This wasn't a stolen password or a leaked token — the attacker manufactured legitimate publishing credentials by exploiting the CI system's own identity infrastructure.

The compromise wasn't limited to TanStack. Community member @varunsharma07 confirmed that @mistralai/mistralai's npm package was hit by the same worm mechanism, indicating this was an automated, self-propagating attack rather than a manually targeted campaign. Mistral's compromised package has since been pulled from the registry.

Why it matters

This attack exposes three uncomfortable truths about the JavaScript ecosystem's publishing infrastructure.

First, Trusted Publishing is necessary but not sufficient. As commenter jonchurch_ noted, this is evidence that Trusted Publishing alone cannot secure CI-based publishing. TP was designed to eliminate long-lived credentials, and it succeeds at that. But when an attacker gains code execution inside your CI pipeline — through cache poisoning, workflow misconfiguration, or stolen repo admin credentials — they inherit whatever publishing authority that pipeline has. Trusted Publishing shifts the trust perimeter from "who has the token" to "who controls the CI environment," but many teams haven't adjusted their threat models accordingly.

Second, npm's safety mechanisms became an obstacle during incident response. The TanStack team discovered that npm's "no unpublish if dependents exist" policy — designed to prevent the left-pad catastrophe — blocked them from removing malicious packages. They had to wait for npm's security team to pull tarballs server-side. As commenter ezekg highlighted, this added hours of delay during which every `npm install` of affected packages was pulling attacker-controlled code. The policy that protects the ecosystem from accidental breakage actively slowed remediation of a deliberate attack, leaving a multi-hour window where malicious tarballs were installable.

Third, GitHub's shared object storage model for forks creates a subtle but dangerous attack surface. Commenter chrisweekly pointed out that an "orphan" commit pushed to a fork could trigger this chain because GitHub's fork architecture shares object storage between forks and their upstream repositories. Commits in a fork are reachable via the parent repo's URI namespace. This isn't a bug — it's how Git's object model works — but it means the trust boundary between a fork and its upstream is thinner than most maintainers assume.

The dead-man's switch payload deserves special attention. As cube00 detailed, the malicious versions install a persistent daemon — a systemd user service on Linux (`~/.local/bin/gh-token-monitor.sh`) or a LaunchAgent on macOS (`com.user.gh-token-monitor`) — that polls `api.github.com/user` with stolen tokens at regular intervals. If you revoke a compromised token without first killing this daemon, the polling failure could trigger secondary payloads — credential revocation must follow a specific order: kill the daemon first, then revoke.

The attack chain, step by step

For practitioners evaluating their own exposure, the full chain matters:

1. Pwn Request via `pull_request_target`: Attacker opens a PR from a fork. The target repo's workflow runs with base-repo permissions, but the attacker controls the PR's code, including cached dependencies.

2. Cache poisoning: The forked PR injects a poisoned entry into the GitHub Actions cache. When the base repository's CI runs (possibly on merge or on a subsequent workflow), it restores the attacker's cached artifacts.

3. OIDC token extraction: With code execution inside the runner, the attacker reads the OIDC token from the runner's environment or memory. This token is the Trusted Publishing credential — it proves to npm that the publish request comes from an authorized CI workflow.

4. Mass publish: Using the extracted OIDC token, the attacker publishes malicious versions across all 42 @tanstack/* packages. The versions contain postinstall scripts that install the persistent dead-man's switch daemon.

5. Worm propagation: The same technique is applied to other repositories with similar workflow configurations, hitting @mistralai/mistralai and potentially others not yet disclosed.

This chain exploits no single zero-day. Every component — `pull_request_target` risks, cache poisoning, OIDC token theft from runners — has been documented and warned about individually. The sophistication is in the composition.

What this means for your stack

Immediate actions (do these today):

- Check your lockfile for any @tanstack/* versions published on May 11, 2026. If found, pin to the last known-good version before that date and run a clean install. - Search CI runners and developer machines for `gh-token-monitor.sh` (Linux: check `~/.local/bin/` and `systemctl --user list-units`) or `com.user.gh-token-monitor` (macOS: check `~/Library/LaunchAgents/`). Remove the daemon *before* revoking any GitHub tokens. - If you use @mistralai/mistralai, verify your installed version against the advisory.

Workflow hardening (do this week):

- Audit every GitHub Actions workflow that uses `pull_request_target`. If the workflow checks out PR code or uses PR-provided inputs, it's vulnerable to this class of attack. The safe pattern is to only use `pull_request_target` for labeling or commenting — never for building or testing PR code. - Enable npm provenance on your packages and verify provenance signatures on your dependencies — this won't prevent a compromised CI from publishing, but it creates an auditable chain that makes post-incident forensics faster. - Scope your OIDC token permissions to the minimum necessary. If your publish workflow only needs to publish package X, restrict the token's audience and claims accordingly. - Consider pinning GitHub Actions by commit SHA rather than tag, and enable the `actions/cache` with a restricted key namespace that separates fork and base workflows.

Strategic reassessment:

If you maintain popular open-source packages published via CI, your threat model now includes "attacker gains code execution inside my CI runner." Trusted Publishing is a strong default, but it's a credential mechanism, not a sandbox. The real defense is minimizing what an attacker can do once they're inside the runner: short-lived tokens with narrow scopes, isolated build environments, and publish pipelines that require an out-of-band approval step for new versions.

Looking ahead

This attack will accelerate several trends already in motion. npm will face renewed pressure to allow emergency unpublishing for security incidents, or to implement a "quarantine" mode that blocks installs of flagged versions without fully unpublishing. GitHub will likely tighten the `pull_request_target` defaults or add warnings when workflows combine this trigger with cache restoration. And the broader ecosystem will have to reckon with the fact that CI/CD pipelines are now the primary attack surface for supply-chain compromises — not developer laptops, not leaked tokens, but the automation infrastructure itself. The 84 malicious packages published in a single incident make that case impossible to ignore.

Hacker News 1073 pts 451 comments

Postmortem: TanStack npm supply-chain compromise

<a href="https:&#x2F;&#x2F;github.com&#x2F;TanStack&#x2F;router&#x2F;issues&#x2F;7383" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;TanStack&#x2F;router&#x2F;issues&#x2F;7383</a>

→ read on Hacker News
cube00 · Hacker News

Please be careful when revoking tokens. It looks like the payload installs a dead-man&#x27;s switch at ~&#x2F;.local&#x2F;bin&#x2F;gh-token-monitor.sh as a systemd user service (Linux) &#x2F; LaunchAgent com.user.gh-token-monitor(macOS). It polls api.github.com&#x2F;user with the stolen token every

Ciantic · Hacker News

What I want to focus on is mental model of your CI pipeline, and problem with too much YAML, consider this quote:&gt; Cache scope is per-repo, shared across pull_request_target runs (which use the base repo&#x27;s cache scope) and pushes to main. A PR running in the base repo&#x27;s cache scope can

jonchurch_ · Hacker News

It is unfortunate, but this is evidence (IMO) that Trusted Publishing is still ~~not secure~~ not enough by itself to securely publish from CI, as an attacker inside your CI pipeline or with stolen repo admin creds can easily publish. This isnt new information, TP is not meant to guarantee against t

chrisweekly · Hacker News

Postinstall scripts are deadly. Everyone should be using pnpm.Crazy that an &quot;orphan&quot; commit pushed to a FORK(!) could trigger this (in npm clients). IMO GitHub deserves much of the blame here. A malicious fork&#x27;s commits are reachable via GitHub&#x27;s shared object storage at a URI in

varunsharma07 · Hacker News

@mistralai&#x2F;mistralai npm package was also compromised as part of this worm https:&#x2F;&#x2F;github.com&#x2F;mistralai&#x2F;client-ts&#x2F;issues&#x2F;217It has been pulled from the npm registry now.

// share this

// get daily digest

Top 10 dev stories every morning at 8am UTC. AI-curated. Retro terminal HTML email.