Skip to main content

Command Palette

Search for a command to run...

The Axios npm supply chain attack: a North Korean trojan inside the world's most popular HTTP library

Published
6 min read
The Axios npm supply chain attack: a North Korean trojan inside the world's most popular HTTP library
D
building infra so agents can use your SaaS @Hintas

On March 31, 2026, someone hijacked the npm account of the lead Axios maintainer and published two poisoned versions of one of the most-downloaded packages in the JavaScript ecosystem. Axios pulls over 100 million weekly downloads. If you've built anything in JavaScript in the last five years, it's probably in your dependency tree.

The malicious versions, 1.14.1 and 0.30.4, silently installed a cross-platform Remote Access Trojan through a dependency called plain-crypto-js. The attack window lasted about three hours, from 00:21 to 03:29 UTC. In that window, anyone who ran npm install and resolved to those versions got owned.

Three hours. That's all it took.

How the attack worked

The attacker didn't touch GitHub. No pull request, no compromised CI/CD pipeline, no poisoned GitHub Actions workflow. They stole a publishing token and used it to push directly to the npm registry. GitHub's code review process, branch protections, and audit logs were all irrelevant. The malicious code never existed in the source repository.

That's what makes registry-level attacks different from everything else in the threat model. Your code review is useless because there's nothing in the repo to review. The malware only exists in the published package, which is the thing your users and build systems actually install.

The payload was staged carefully. The plain-crypto-js dependency was pre-registered 18 hours before the poisoned Axios versions went live. On install, it ran platform-specific payloads: a binary at /Library/Caches/com.apple.act.mond on macOS, %PROGRAMDATA%\wt.exe on Windows, and /tmp/ld.py on Linux. The RAT called home to sfrclak.com on port 8000, with callback URLs disguised as npm traffic (packages.npm.org/product0, product1, product2 for each platform).

The malware harvested cloud access keys, database passwords, API tokens, SSH keys, and anything else it could find in environment variables and credential files. It wrote persistence hooks into .bashrc and .zshrc. Once installed, the attacker had a persistent foothold on your machine, surviving reboots and terminal restarts.

Encryption was AES-256 for the data itself, RSA-4096 for the session key. Not amateur work.

The TeamPCP campaign

The Axios compromise wasn't an isolated incident. It was the fifth in a two-week spree by a group researchers call TeamPCP.

Here's the timeline:

March 19: Aqua Security's Trivy, one of the most widely used container vulnerability scanners. TeamPCP exploited an incomplete credential rotation from a minor breach in late February, force-pushed malicious code to 76 of 77 version tags in aquasecurity/trivy-action, and poisoned all tags in setup-trivy. Every automated pipeline running Trivy scans was executing attacker code before the scan even started. The payload evolved through three versions, the last of which, CanisterWorm, included self-replication and a wiper component.

March 23: Checkmarx KICS, another infrastructure-as-code security scanner. Stolen GitHub tokens from the Trivy compromise enabled force-pushing to all 35 version tags. The irony of security scanners being weaponized to steal credentials from the CI/CD pipelines they're supposed to protect was not lost on anyone.

March 24: LiteLLM on PyPI, the popular AI proxy library with 95M+ monthly downloads. Versions 1.82.7 and 1.82.8 shipped with payloads that exfiltrated to models.litellm.cloud. The second version used .pth file execution to run at Python interpreter startup and installed a systemd service called sysmon.service for persistence.

March 27: Telnyx on PyPI. Versions 4.87.1 and 4.87.2 used a more creative exfiltration method, embedding encrypted data inside audio frames of WAV files. Eight bytes of XOR-encrypted data followed by the eight-byte key to decrypt it, hidden in sound files.

March 31: Axios on npm. The biggest target, the broadest blast radius.

Five major packages across two registries in 12 days. SANS analysts believe TeamPCP is sitting on a stockpile of compromised publishing credentials and operating as an Initial Access Broker, selling access to other threat groups. They've since announced a partnership with the Vect ransomware group on BreachForums, which means the credential theft is likely a precursor to extortion operations.

The numbers from Palo Alto's Unit 42 analysis are grim: 300+ GB of data exfiltrated, 500,000 infected machines, 16+ victim organizations publicly announced, and 48 additional packages compromised through harvested tokens. From the initial Trivy breach, TeamPCP was able to identify and infect 47 additional npm packages within 60 seconds using stolen tokens.

The collision with Claude Code

The Axios attack happened on the same day, nearly the same hour, as Anthropic's accidental Claude Code source leak. Two completely unrelated incidents converging on the npm registry within hours of each other.

Anyone who installed Claude Code via npm between 00:21 and 03:29 UTC could have pulled in the poisoned Axios as a transitive dependency. The source leak gave attackers a bonus: they immediately began typosquatting internal package names found in the leaked code. Five internal dependencies were squatted before the day was out: audio-capture-napi, color-diff-napi, image-processor-napi, modifiers-napi, url-handler-napi.

The convergence of these two incidents did more damage to npm's credibility in a single day than years of smaller incidents combined. Anthropic now recommends its native installer over npm for Claude Code installations.

Why npm's trust model is broken

The core problem: npm trusts whoever holds the publishing token. No mandatory two-factor authentication for publishing. No OIDC provenance linking a published package back to a specific CI/CD run. No verification that what gets published matches what's in the source repository.

The Axios attacker didn't need to compromise any code. They needed one stolen token. That token gave them the ability to publish arbitrary code under a trusted package name to 100 million weekly consumers with zero human review.

SLSA (Supply chain Levels for Software Artifacts) defines a framework for exactly this problem. At SLSA Build Level 3, a package's provenance is cryptographically verifiable and tied to a specific source commit and build environment. npm supports provenance attestations as of 2023, but they're optional. The Axios package didn't have them. Neither did Trivy, KICS, LiteLLM, or Telnyx.

Optional security doesn't work when the attacker only needs to find one package without it.

Coder's analysis of the incidents makes a broader architectural argument: when a developer or AI agent operates inside an isolated workspace, a compromised dependency can't reach the corporate network, exfiltrate credentials, or pivot to production. The defense isn't just better lockfiles. It's infrastructure that assumes dependencies will be compromised and contains the blast radius by design.

What you should do right now

If you installed or updated any npm packages on March 31 between 00:21 and 03:29 UTC, check your lockfile for axios@1.14.1 (SHA-1: 2553649f2322049666871cea80a5d0d6adc700ca) or axios@0.30.4 (SHA-1: d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71). Search for plain-crypto-js anywhere in your node_modules. If you find either, assume compromise.

Rotate everything. npm tokens, cloud access keys (AWS, Azure, GCP), SSH keys, database passwords, API tokens. Check your shell profiles (.bashrc, .zshrc) for injected lines. Look for RAT artifacts: /Library/Caches/com.apple.act.mond on macOS, %PROGRAMDATA%\wt.exe on Windows, /tmp/ld.py on Linux. Block sfrclak.com and 142.11.206.73 at the network level.

Going forward: pin exact versions in your lockfile and treat lockfile changes as security-relevant code reviews. Enable npm provenance for your own packages. Run npm audit signatures regularly. Consider package age policies that reject packages published less than 24 hours ago, which would have caught this attack entirely since the malicious plain-crypto-js was only 18 hours old when it was pulled in.

And look at your development environment architecture. If a compromised npm dependency can reach your AWS credentials, your Kubernetes configs, and your production database passwords from a developer laptop, the problem isn't just npm. It's that your security boundary is the developer's machine, and that boundary doesn't hold.

We've written before about how unvetted MCP servers are attack surfaces and why agent permissions need real security boundaries. The Axios attack is the same lesson from a different angle. Whether it's a malicious MCP server, a compromised npm package, or a RAT disguised as a crypto library, the question is the same: what can it reach when it runs, and what happens when it does?

The TeamPCP campaign answered that question for 500,000 machines.


If you're interested in early access, reach out at hintas.com.

Photo by Nicolas HIPPERT on Unsplash

More from this blog

H

Hintas

18 posts

AI agents, MCP, and workflow automation in production. We cover why AI projects fail, how to secure agent infrastructure, and what it takes to make AI actually work inside SaaS — from protocol design to supply chain security.