The Dependency Is the Backdoor: Anatomy of the TanStack npm Compromise
You can build a messenger with flawless cryptography, audit every line, and ship it to users who trust it — and an attacker can still own all of them without breaking any of it, by poisoning a library you depend on. A compromised dependency runs inside your application, with all of its privileges. It doesn’t need to defeat your encryption. It already lives behind it.
On 11 May 2026, the JavaScript ecosystem got a precise, well-documented demonstration. Attackers compromised TanStack, the popular set of open-source libraries (Router, Query, Start), publishing 84 malicious versions across 42 @tanstack/* packages in a roughly six-minute window. The maintainers’ postmortem is unusually transparent, and it’s worth dissecting, because every step generalizes far beyond one project.
The six-minute window
The malicious versions went live between 19:20 and 19:26 UTC. Two poisoned releases were pushed for each of 42 packages. Anyone who ran an install and pulled a fresh version in that window — or in the time before the packages were yanked — could have executed attacker code on their machine or, worse, in their build pipeline.
What makes this case instructive isn’t that it happened. Supply-chain compromises happen constantly now. It’s how it happened: a chain of three individually-plausible weaknesses that, combined, handed attackers the keys to publish.
Step 1: a pull request that runs code
The entry point was a GitHub Actions workflow using the pull_request_target trigger.
This trigger is a well-known footgun, and understanding why is the whole lesson. A normal pull_request workflow runs with low privileges and no access to the repository’s secrets — sensible, because the code in a pull request comes from strangers. But pull_request_target is different: it runs in the context of the base repository, with access to secrets, while checking out code that an outside contributor controls.
attacker forks repo → opens a PR → pull_request_target workflow fires
│ runs in TRUSTED context (has secrets)
│ but executes attacker-controlled PR code
▼
attacker code now runs with the repo's privileges
This pattern — sometimes called a “Pwn Request” — means an outsider’s code executes in a trusted context. In TanStack’s case the offending workflow was a bundle-size check. A check on the size of a build became the door.
Step 2: poisoning the cache across the trust boundary
Running code in CI isn’t, by itself, game over — unless you can make the damage persist and spread. The attackers did that with GitHub Actions cache poisoning.
CI systems cache build artifacts and dependencies to run faster. The attackers used their foothold to plant malicious binaries into the cached package store (a pnpm store) in a way that crossed the trust boundary from the untrusted fork context into the trusted base-repository builds. A later, legitimate-looking run would pull the poisoned cache and treat it as its own clean dependencies. The poison laundered itself into the trusted pipeline.
Step 3: stealing the key that signs releases
The prize was an OIDC token. Modern CI/CD uses short-lived OpenID Connect tokens to authenticate to package registries and cloud providers without long-lived secrets — generally a security improvement. But a token that exists in the runner’s memory can be stolen by code running on that runner.
The attackers performed runtime memory extraction of the OIDC token from the GitHub Actions runner process. With that token, they could mint publish-capable credentials and push releases to npm that looked, to every check and every consumer, completely legitimate — because they were signed with the project’s own authority.
That is the anatomy of the whole attack: a dangerous trigger to run code, cache poisoning to persist and cross the trust boundary, and token theft to seize publishing rights. None of it touched a single user’s cryptography. It didn’t have to.
What the payload did
The published malware was a roughly 2.3 MB obfuscated install-time script — code that runs automatically when a developer installs the package. Its job was credential theft on an industrial scale. It harvested:
- AWS instance metadata (IMDS) and Secrets Manager values
- GCP metadata-server credentials
- Kubernetes service-account tokens
- HashiCorp Vault tokens
~/.npmrc(your npm auth) and GitHub tokens- SSH private keys
In other words: the master keys to a developer’s entire cloud and source-control footprint. One poisoned npm install in the wrong environment, and an attacker can pivot into production infrastructure, private repositories, and every system those credentials unlock — the seed of a self-propagating compromise, where stolen publishing tokens are used to poison the next set of packages.
The exfiltration twist: encryption as the attacker’s tool
The most pointed detail for a privacy-focused audience: the stolen secrets were exfiltrated over the Session/Oxen messenger’s file-upload network — end-to-end encrypted, routed through that network’s infrastructure, with no attacker-controlled command-and-control server to seize or block.
Sit with that for a moment. Strong, decentralized encryption — the same category of tool we build — was used by attackers to smuggle out their loot, precisely because it’s hard to surveil and hard to take down.
This is not an argument against encryption. It’s a reminder that encryption is infrastructure, and infrastructure is dual-use — the same property that protects a journalist’s source protects an attacker’s exfiltration. The honest response isn’t to weaken encryption (which would harm only the lawful users, since attackers can always roll their own). It’s to recognize that the defense against this attack was never going to be at the network layer. It was upstream, in the supply chain itself.
The one piece of good news: it was caught fast
The compromise was detected within roughly 20 to 26 minutes by an external researcher who spotted the malicious dependency fingerprint. That speed mattered — it limited exposure dramatically. But “a sharp-eyed outsider noticed in time” is not a security control you can plan around. It’s luck wearing a lab coat. And this was one well-documented incident in a broader, ongoing wave of npm and registry worms that security firms have tracked through 2025 and 2026 — the trend, not the exception.
Why this shapes how RVNT is built
A secure messenger is only as trustworthy as the code that actually ships to your device — and that includes every dependency in the build. The TanStack incident is exactly the threat model behind several of RVNT’s least glamorous, most important choices.
- A small, scrutinized dependency surface. Every dependency is code you are trusting with everything your application can do. The defense starts with having fewer of them and vetting what remains. The most secure dependency is the one you didn’t add.
- The security-critical core is Rust, not JavaScript. RVNT’s cryptography and protocol live in a Rust core, and we have a hard rule: no cryptography in JavaScript/TypeScript. That isn’t a language preference — it’s an attack-surface decision. The npm ecosystem’s install-time-script model (the very mechanism this payload abused) is uniquely exposed to this class of attack. Rust’s
cargohas its own supply-chain risks, but it does not auto-execute arbitrary install scripts from every transitive dependency the same way, and keeping the crypto out of the most-targeted ecosystem is deliberate. The use of a memory-safe language also closes the parsing-bug classes that other attacks rely on. - Builds you can reproduce and verify. The deepest answer to “did the code I audited become the binary I’m running?” is a reproducible build — one where anyone can rebuild from source and get a bit-for-bit identical artifact, so a tampered release stands out. This is why RVNT documents how to build and how to verify what you run, rather than asking you to trust a download.
- Open source so the supply chain is inspectable. RVNT is open source under AGPLv3. A poisoned dependency or a suspicious build step is something the public can find — the same way an outside researcher caught TanStack in 26 minutes. Closed code gets none of that scrutiny.
The honest limit
No project is immune to this, and we won’t claim RVNT is. Supply-chain security is a posture, not a finish line. Any project with dependencies, contributors, and a CI pipeline has surface here — the questions are how much, how well-watched, and how verifiable. A determined, well-resourced attacker who compromises a critical upstream is a serious threat to everyone, including us, and pretending otherwise would be exactly the kind of overconfidence this attack punishes.
What you can reasonably demand of a tool you trust with your private communication is that it takes the supply chain seriously by design: a minimal and audited dependency set, the crypto kept out of the most-abused ecosystem, builds that can be independently reproduced, and everything open to inspection. Those are choices, and they’re checkable.
So check them. Read how to verify a build, inspect the architecture, and confirm for yourself that the path from source to the app on your device is one you can follow — because the dependency you can’t see is the one that becomes the backdoor.
Keep reading
All posts →-
The Anthropic Recall: How Centralized AI Threatens Decentralized Privacy
A breakdown of today's US government export control directive targeting Anthropic, the vulnerabilities of centralized AI architectures, and why decentralized, sovereign communications are vital.
5 min read -
Sealed Sender: Hiding Who Talks to Whom
A technical deep-dive on RVNT's sealed sender: how encrypting the sender certificate to the recipient hides the from-to routing pair, and how forgery, replay, and abuse are handled.
9 min read -
Chat Control, Explained: The EU's Fight Over Scanning Your Messages
EU Chat Control explained: what the CSA Regulation proposes, why client-side scanning breaks end-to-end encryption, the 2025-2026 timeline, and its current status.
11 min read -
Meta Won in Court. NSO Allegedly Kept Hacking Anyway.
In June 2026 Meta asked a US court to hold NSO Group in contempt for defying the injunction that bars it from targeting WhatsApp. The case is a stress test of whether courts can stop mercenary spyware — and a reminder that the endpoint, not the encryption, is the battleground.
9 min read -
Metadata Is the Message
"It's just metadata" is a dangerous phrase. Who you talk to, when, and how often can reveal more than what you said — and RVNT is built to minimize it.
9 min read -
Can Your Employer Read Your Messages? Workplace Surveillance Explained
Can my employer read my messages? Yes for work email, Slack and Teams DMs, and company devices. Here's what they legally can and can't see in 2026 — and how to separate personal from work.
11 min read -
Nobody Broke the Encryption: Inside the 2026 Vishing Breach Wave
Charter, Carnival, DentaQuest — millions of records gone this spring, and not one attacker touched the cryptography. They phoned an employee. Why the centralized account, not the cipher, is the real attack surface.
8 min read -
RVNT vs Signal: An Honest Comparison
Signal is the gold standard for encrypted messaging. Here is where RVNT agrees, where it diverges, and the honest tradeoffs of each — no strawmen.
10 min read