- Endor Labs reports that 84 malicious @tanstack versions reached npm on May 11, 2026, with valid provenance, despite 2FA and trusted publishing.
- The attacker used the maintainers' own release workflow, so checks built to catch stolen credentials had nothing to flag.
- Leaders should have teams audit pull_request_target workflows, cache use in publish jobs, and where id-token: write is granted.
A signature proves who signed. It does not prove whose hand held the pen. A May 2026 attack on TanStack's npm packages shows why that gap matters to anyone who ships or installs software.
Every control was on, and it still worked
Endor Labs, a security vendor, published a technical analysis on October 12 of the May 11 attack. In about six minutes, starting at 19:20 UTC, an attacker released 84 poisoned versions across 42 @tanstack packages on npm.
The packages carried valid SLSA provenance. That is a signed record of where a package was built. Here, the record pointed to the real TanStack repository.
The team had followed the standard advice. Every maintainer used two-factor login. Releases used npm trusted publishing, which swaps stored passwords for short-lived tokens. Each release carried provenance.
Endor Labs says the maintainers' postmortem found no stolen npm credential. No maintainer account was taken over. Branch protection held. So did the link between npm and the release workflow.
How the chain worked
Endor Labs describes three known weaknesses in GitHub Actions, linked together. Each one appears in public research.
First, a workflow used a trigger called pull_request_target. It runs with the trust of the main repository, not the outsider's. This workflow also ran code from an attacker's copy of the project. Endor Labs calls that a "Pwn Request". GitHub Security Lab named the pattern in 2021.
Second, the attacker poisoned the build cache. A cache is saved work that later runs reuse to go faster. Cache names come from public files. So an attacker can work out the name the release will ask for.
The cache save uses an internal runner token. Tight permissions on the job did not stop it.
Then the attacker covered their tracks. They reset the pull request to a clean state, closed it and deleted the branch. The poisoned cache stayed in place.
Third, the attacker waited. Eventually, an unrelated maintainer merged a routine change to main. That started the release workflow. It loaded the poisoned cache. Attacker code now ran inside the genuine job.
Lifting a token that was never stored
Trusted publishing swaps stored passwords for a short-lived token. The workflow asks GitHub for it when needed. The token lives only in memory.
The attacker's code read that memory on the build machine. It took the token and contacted the npm registry directly.
The workflow's own publish step did not run, because tests failed. The packages went out anyway, from inside the same run. Endor Labs says the memory-reading method matches the one used in the tj-actions/changed-files compromise in March 2025.
The poisoned packages pointed to a hidden GitHub commit. That code ran when anyone installed them. Endor Labs says it collected credentials widely.
What provenance can and cannot say
The record said release.yml built the packages on main in tanstack/router. That was true. But it cannot show which step in the workflow ran the publish.
The lesson here is about trust. Today's checks are built for stolen passwords and direct break-ins. In this case, each defense worked as designed. The attacker used that correct behavior as a bridge.
A provenance badge tells you which factory shipped the box. It does not tell you whose hands packed it.
Endor Labs argues that GitHub needs stronger walls between jobs that restore caches and jobs that publish. Until then, each workflow author must reason about these limits alone. That is a vendor's view. But the mechanism it describes is specific and can be checked.
Endor Labs also says an outside researcher first detected the attack. Monitoring inside the pipeline did not.
Questions to put to your team
Ask whether any workflow uses pull_request_target and runs code from a pull request. Endor Labs advises switching it to a plain pull_request. The other option is to split build work and comment work into two workflows.
Ask whether publish jobs restore caches. Endor Labs recommends treating the cache as untrusted there. Ask whether id-token: write is granted to one dedicated publish job or to the whole workflow.
Ask whether publishing needs a human approval step. Endor Labs notes that a token stolen from memory cannot pass a human gate.
Ask whether outbound traffic from build machines is monitored. Ask whether third-party actions are pinned to commit SHAs.
If anyone installed an affected version, Endor Labs advises rotating every credential reachable from that machine. That covers GitHub, npm, cloud, Kubernetes, Vault and SSH.
Produced by the WebPulse Newsroom with AI assistance from the original reporting credited below, and checked against that source by our editorial review. How we use AI.
Original reporting: Endor Labs.





