TanStack Got Compromised โ What It Means for Your npm Dependencies ๐
TanStack packages โ @tanstack/query, @tanstack/router, @tanstack/table โ collectively pull tens of millions of weekly downloads. They sit deep in dependency trees across a huge number of production apps. In early 2026, an attacker obtained an npm publish token from TanStack's CI pipeline and used it to push malicious versions of several packages. Obfuscated postinstall hooks phoned home to attacker infrastructure. The window was short โ hours โ but hours is a lot of npm install runs.
This isn't a new pattern. The same playbook worked against lottie-player in 2025 and ua-parser-js in 2021. What changes each time is the name on the package and the number of people scrambling. This post walks through what happened, why the pattern keeps repeating, and what you can do about it today.
What Happenedโ
The short version: an attacker compromised an npm automation token used in TanStack's GitHub Actions CI/CD pipeline. With that token, they published malicious versions of @tanstack/config, @tanstack/query, @tanstack/router, @tanstack/table, and other packages in the TanStack org.
The malicious versions contained obfuscated code in postinstall hooks โ scripts that run automatically after npm install. The code called out to attacker-controlled infrastructure. The community noticed unexpected version bumps within hours. The TanStack team responded quickly: revoked the token, unpublished the malicious versions, republished clean releases, and published a detailed postmortem.
One detail is worth highlighting: automation tokens exist specifically to bypass 2FA. That's their purpose โ you can't enter a TOTP code in a CI pipeline. It's also their risk. If the token leaks, an attacker can publish as the package owner without any second factor. The token is the keys.
The TanStack team's postmortem is thorough and worth reading in full: TanStack npm Supply Chain Compromise Postmortem.
Why This Keeps Happeningโ
The CI/CD token compromise is becoming the dominant supply chain attack vector in the npm ecosystem. It works because the security model has an inherent tension: automation tokens must bypass interactive authentication, but that bypass is exactly what makes them valuable to attackers.
This is the same vector that hit lottie-player in October 2025 โ a compromised publish token, malicious versions pushed, users affected before anyone noticed. Months apart, same playbook, same result.
Other npm supply chain attacks have used different mechanics to reach the same outcome:
- ua-parser-js (2021) โ the maintainer's npm account was taken over directly. Different entry point, same result: malicious code in a trusted package.
- event-stream (2018) โ a new maintainer was social-engineered into the project and added a malicious dependency. No credential theft at all โ just trust.
The common thread isn't a single vulnerability. It's that npm's publishing model is optimized for low friction, and any credential or trust relationship that can be compromised gives an attacker the ability to push code to millions of machines.
The other factor is the window of exposure. Even "hours" is enough. CI pipelines run around the clock. Developers run npm install on new projects. Lock files get regenerated. A malicious version published at 2 AM UTC can land in production builds before anyone in the maintainer's timezone wakes up.
For a deeper look at the full taxonomy of npm supply chain attack vectors, see npm Supply Chain Attacks in our docs.
What You Can Do Right Nowโ
These are the most relevant actions for this specific class of attack โ CI/CD token compromise leading to malicious package versions.
-
Check if you installed a malicious version. If you use any TanStack packages, verify your lock file. Run:
npm ls @tanstack/query @tanstack/router @tanstack/tableCompare the installed versions against the known-good versions listed in the TanStack postmortem. If you find a malicious version, delete
node_modules, revert your lock file to a known-good commit, and reinstall. -
Use
npm ciin CI, always. Thenpm cicommand installs exactly what your lock file specifies, nothing more. If your lock file pins@tanstack/query@5.62.0and an attacker publishes5.62.1,npm ciwon't pick it up.npm installmight, depending on your version ranges. This single practice blocks most "surprise version" attacks. -
Disable install scripts. This attack used
postinstallhooks โ scripts that run automatically duringnpm install. You can disable them globally:.npmrcignore-scripts=trueMost packages work without install scripts. Test your build after enabling this to identify any that need them. See Ignore Install Scripts in our docs.
-
Audit your own npm publish tokens. If you maintain packages, treat your automation tokens like production database credentials:
- Use granular access tokens scoped to specific packages
- Set short expiry windows โ 90 days or less
- Rotate them on a schedule, not just after incidents
- Store them in your CI platform's secret management, never in repository files
cautionAutomation and publish tokens bypass 2FA by design. A leaked token gives an attacker full publish access to every package the token covers. Scope them as narrowly as possible and rotate them aggressively.
-
Set a minimum release age policy. Both npm 11+ and pnpm support quarantine windows that refuse to install any version published less than a configured duration ago.
tipA minimum release age of 3โ7 days would have blocked every version published during the TanStack incident. The malicious versions were unpublished within hours.
npm (v11+) โ add to
.npmrc:.npmrcmin-release-age=7pnpm โ add to
package.json:package.json{
"pnpm": {
"minimumReleaseAge": "3d"
}
} -
Run behavioral analysis tools.
npm auditchecks against the npm advisory database โ but advisories are published after an incident is discovered and reported. During the active attack window,npm auditwould have shown nothing. Tools like Socket.dev analyze actual package behavior โ network calls, filesystem access, obfuscated code โ and can flag malicious versions before an advisory exists.
For the full checklist of npm security practices, see the npm Security Checklist in our docs.
The Bigger Pictureโ
The npm trust model was designed for a world where publishing speed mattered more than publishing safety. That was a reasonable trade-off when the ecosystem was small. It is a less reasonable trade-off when npm install runs on millions of machines daily and a single publish token can push code to all of them.
The most promising structural fix is npm provenance. Built on Sigstore, provenance ties a published package version to a specific source commit and build workflow. If a version has a valid provenance attestation, you can verify it was built from the source you can inspect โ not from an attacker's laptop using a stolen token. Provenance doesn't prevent all attacks, but it makes token-only compromises verifiable after the fact and detectable during install.
No single tool or practice solves supply chain security. Defense is layers: lock files and npm ci prevent surprise upgrades, token hygiene reduces the attack surface, behavioral scanning catches what advisory databases haven't cataloged yet, and provenance links published artifacts back to source. Each layer catches what the others miss.
TanStack's response to this incident was fast and transparent. The postmortem names what went wrong, how the team responded, and what they changed. That kind of transparency makes the entire ecosystem more resilient. It's worth reading in full.
