“Socket detected 84 compromised TanStack npm package artifacts modified with suspected CI credential-stealing malware.” — @SocketSecurity
https://socket.dev/blog/tanstack-npm-packages-compromised-mini-shai-hulud-supply-chain-attack
“Socket detected 84 compromised TanStack npm package artifacts modified with suspected CI credential-stealing malware.” — @SocketSecurity
https://socket.dev/blog/tanstack-npm-packages-compromised-mini-shai-hulud-supply-chain-attack

On 2026-05-11, an attacker chained a pull_request_target Pwn Request, GitHub Actions cache poisoning across the fork↔base trust boundary, and OIDC token extraction from runner memory to publish 84 malicious versions across 42 @tanstack/* packages on npm. Full postmortem.
A follow up here on action items (assuming you’re already using trusted publishers OIDC to scope releases to a single GitHub Action workflow):
1. Look for any `pull_request_target` GitHub Actions workflows! (this allows external forks/code to run your actions with write access ☠️☠️☠️☠️☠️)
2. Look for use of `cache` in your GitHub Actions release workflow (cache was poisoned/compromised by `pull_request_target` trigger)
Learn more about `pull_request_target`: https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/
Importantly, `pull_request_target` IGNORES this GitHub security setting: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#controlling-changes-from-forks-to-workflows-in-public-repositories
This was very surprising to me.
@zachleat I’m not trying to be rude. I’m genuinely trying to figure out what makes this a masterclass retro.
It does include a lot of details, but doesn’t mention the dead man’s switch that was posted 3 hours ago https://github.com/TanStack/router/issues/7383#issuecomment-4425225340 and has exactly one general line on what owners of compromised machines should do.
Did I miss something?
@zachleat npm needs to make prepare/postinstall hooks opt-in and allow-listed instead of on by default for the whole universe
and a declarative/sandboxed solution for packages that have to download and compile as an escape hatch (something like flathub's manifest where the framework does the downloading for you and rejects anything that doesn't match the expected hashes)
absurd that even crates.io has the same problem and no solution in sight :S