TanStack supply-chain attack publishes 84 malicious NPM packages
Serge Bulaev
An attacker may have used a misconfigured workflow in TanStack's GitHub Actions to publish 84 malicious NPM packages very quickly. The attack appears to have used untrusted code in a pull request to poison a shared cache, which then let the attacker publish bad packages using a short-lived token. TanStack says no NPM tokens were stolen and the publishing process itself was not directly compromised. This incident suggests that even short-lived credentials can be risky if untrusted code is run in the same workflow. It also shows that these kinds of attacks might spread quickly to other projects and highlights the need for stronger protections in continuous integration setups.

The TanStack supply-chain attack saw an attacker exploit a misconfigured GitHub Actions workflow to publish 84 malicious NPM packages in just six minutes. This sophisticated exploit used untrusted code from a pull request to poison a shared build cache, allowing the attacker to hijack the legitimate release process without ever stealing long-lived credentials. This incident highlights critical vulnerabilities in modern CI/CD pipelines and the need for stronger security hygiene.
How the Attack Unfolded
The TanStack supply-chain attack exploited a GitHub Actions workflow misconfiguration. An attacker submitted a pull request with malicious code that poisoned a shared pnpm cache. A subsequent, trusted release process then used this poisoned cache, inadvertently executing the payload and publishing tainted packages with a legitimate, short-lived token.
The attack chain began when a pull request from a forked repository triggered a pull_request_target workflow, which executed the attacker's code and poisoned the cache. Minutes later, the legitimate release.yml workflow restored this cache, executed the hidden payload, and exposed a short-lived OpenID Connect (OIDC) token. Using this token, the script published malicious package versions that appeared to come from a verified source. As Orca Security notes, this was possible because cache writes use a runner token that is "not prevented by permissions: contents: read" (Orca analysis).
Ecosystem Impact and Ripple Effects
The malicious packages propagated rapidly across the software ecosystem. According to Snyk, the tainted dependencies reached projects from Mistral AI, UiPath, and dozens of other maintainers within hours, spreading embedded malware through standard dependency updates. StepSecurity observed similar payloads spreading to non-TanStack packages within a day, suggesting a potential self-propagation capability. While all malicious versions were quickly removed following community alerts, cached artifacts could still exist in private registries.
Key Lessons in GitHub Actions Security
Public analyses point to several known but unmitigated risks in the workflow's design. The official postmortem calls them "known GitHub Actions design issues that require conscious mitigation," highlighting the shared responsibility between platform design and user configuration. Key missteps included sharing caches between untrusted forks and protected branches and granting overly broad id-token permissions.
Teams using GitHub Actions should implement the following best practices:
- Set the default GITHUB_TOKEN to read-only and tightly scope id-token permissions.
- Avoid the pull_request_target trigger, or ensure it is fully isolated from privileged jobs.
- Use separate, isolated caches to prevent untrusted jobs from poisoning release workflows.
- Pin all third-party actions to their full, immutable commit SHAs.
- Mandate code review for any changes to workflow files under .github/workflows/.
A Growing Trend of CI/CD Exploitation
This exploit technique is part of a larger trend of CI/CD pipeline attacks that security researchers have been tracking. While recent incidents at Axios and node-ipc involved account takeovers, the TanStack compromise is a high-profile example of a supply-chain attack driven entirely through CI/CD pipeline abuse. The incident has spurred maintainers to audit their CI/CD configurations, tighten workflow permissions, and adopt stronger OIDC conditions to prevent similar attacks.
How did the attackers publish malicious packages without stealing npm tokens?
The adversary never touched npm credentials.
By chaining three GitHub Actions weaknesses - pull_request_target abuse, cache poisoning, and runtime memory extraction of the OIDC token - they hijacked TanStack's own release workflow.
The legitimate pipeline then signed and published the 84 malicious versions on their behalf.
Which packages and versions were affected?
All poisoned artifacts lived under the @tanstack/* scope.
Multiple packages (including react-query, table, router) received malicious versions, emitted in a six-minute window during the attack.
The complete list is available in the official postmortem.
What does the attack mean for downstream projects?
Even a single install of a tainted version pulls in credential-stealing code that targets cloud keys, registry tokens, and git credentials.
Because TanStack libraries are downloaded millions of times each week, the incident propagated to Mistral AI, UiPath, DraftLab and dozens of other maintainers within hours.
How can teams stop similar CI/CD hijacks?
- Disable default write token - set repository default to
contents: readand elevate only when needed. - Never checkout untrusted code inside
pull_request_target; usepull_requestinstead. - Pin every third-party action to an immutable commit SHA, not a mutable tag.
- Split build and release jobs so packages are built in a low-privilege stage and signed or published in a separate, gated environment.
- Turn on OIDC trusted publishing and keep npm tokens empty; short-lived identity tokens expire in minutes and cannot be reused if extracted.
Where can I check if my builds were exposed?
- Run
npm lsagainst the lock-file and look for any@tanstack/*version published during the attack timeframe. - Compare hashes with the safe list in the TanStack postmortem.
- Audit GitHub Actions workflow YAML for
pull_request_target, unpinned actions, or overly broadpermissionsblocks.