TL;DR
North Korean threat actors hijacked a maintainer account for the axios npm package (100 million weekly downloads) and published two backdoored versions containing a cross-platform remote access trojan. The malicious versions were live for about three hours on March 31 before npm pulled them. If you installed axios@1.14.1 or axios@0.30.4 during that window, your machine is compromised. Rotate every credential on that system immediately.
What Happened
On March 31, 2026, at 00:21 UTC, someone published axios@1.14.1 to npm. Thirty-nine minutes later, axios@0.30.4 followed. Both came from the real maintainer account, jasonsaayman. But jasonsaayman didn’t publish them.
An attacker had obtained a long-lived classic npm access token for the account. They changed the registered email to a ProtonMail address they controlled (ifstap@proton.me), then pushed the poisoned packages. No two-factor authentication stood in the way.
Here’s the thing that makes this attack clever: they didn’t touch a single line of axios source code. Instead, they added one new dependency to package.json:
{
"dependencies": {
"plain-crypto-js": "^4.2.1"
}
}
That’s it. The name looks like it belongs — a crypto utility, maybe a lightweight alternative to crypto-js. But plain-crypto-js@4.2.1 existed for one purpose: to run a postinstall script that drops a RAT on your machine.
How the Attack Chain Works
The execution flow is simple:
You run
npm install. npm resolves axios’s dependency tree, findsplain-crypto-js@4.2.1, downloads it, and runs its postinstall hook automatically.The postinstall script (
setup.js) uses two layers of obfuscation: reversed Base64 with padding character substitution, plus an XOR cipher with the keyOrDeR_7077and a constant value of 333.It checks
os.platform()and downloads a platform-specific binary fromsfrclak[.]com:8000(IP: 142.11.206.73). Windows gets an .exe, macOS gets a Mach-O binary, Linux gets an ELF. All three implement the same C2 protocol.Once running, the RAT collects your hostname, username, OS version, running processes, and timezone. Then it waits for commands. It can execute arbitrary shell commands, run PowerShell scripts, enumerate your entire filesystem, and inject PEs into memory.
Here’s the nasty part: after execution, the dropper deletes
setup.js, removes the maliciouspackage.json, and replaces it with a clean one. If you inspectnode_modules/plain-crypto-js/after the fact, everything looks normal. There’s a 36-second gap between the two file writes, which is the dropper’s execution time.
# What your lockfile looks like if you're affected
# Check for these exact versions:
axios@1.14.1
axios@0.30.4
plain-crypto-js@4.2.1
The 18-Hour Setup
This wasn’t rushed. The attacker staged the operation carefully:
- March 30, 05:57 UTC: A clean
plain-crypto-js@4.2.0is published. Does nothing malicious. Just establishes the package’s presence on npm. - March 30, 23:59 UTC:
plain-crypto-js@4.2.1goes up with the payload baked in. - March 31, 00:21 UTC:
axios@1.14.1ships with the new dependency. - March 31, 01:00 UTC:
axios@0.30.4follows, targeting projects pinned to the 0.x branch. - March 31, ~03:25 UTC: npm removes both compromised versions after Elastic Security Labs filed a GitHub Security Advisory at 01:50 UTC.
The clean decoy package sat there for 18 hours before the real attack. Both the latest and legacy tags were poisoned, and the malicious versions stayed up for about three hours before removal.
Who Did This
Google’s Threat Intelligence Group (GTIG) attributes the attack to UNC1069, a financially motivated North Korea-linked group active since at least 2018.
The fingerprints are specific. The RAT is an updated version of WAVESHAPER, a C++ backdoor Mandiant has tracked across previous UNC1069 operations. WAVESHAPER.V2 upgraded the C2 protocol from raw binary to JSON and added more backdoor commands, but it kept distinctive habits: the C2 URL gets passed as a command-line argument, it polls on the same intervals, and all three platform variants hardcode an Internet Explorer 8 / Windows XP User-Agent string. An IE8 user-agent, in 2026. That’s how you get caught.
Infrastucture analysis seals it. The C2 domain resolved to an IP on an ASN historically associated with UNC1069 operations, and connections from a specific AstrillVPN node previously used by the group were observed hitting the same server.
This fits a pattern. Mandiant CTO Charles Carmakal warned that secrets stolen across recent supply chain attacks, including the LiteLLM and Trivy compromises, will lead to follow-on crypto theft, ransomware, and extortion. The Axios attack may be connected to the broader TeamPCP supply chain campaign that hit four open-source projects between March 19 and 27.
Who’s Affected (and Who Isn’t)
You’re affected if:
- Your
package-lock.jsonoryarn.lockcontainsaxios@1.14.1,axios@0.30.4, orplain-crypto-js@4.2.1 - A CI/CD pipeline ran
npm installwithout a lockfile (or with--no-package-lock) between 00:21 and ~03:25 UTC on March 31 - You ran
npm install axiosornpm updateduring that window
You’re probably safe if:
- Your lockfile was committed before March 31 and your install didn’t update it
- You use
npm ci(which respects the lockfile exactly) - You had
--ignore-scriptsenabled
End users of apps built with axios are not directly affected. The infection path is the install/build step. The RAT targets developer machines and CI environments, not application runtime.
Wiz estimates axios is present in about 80% of cloud and code environments they scan. So far, they’ve observed the malicious versions in roughly 3% of scanned environments. That’s a lot of potentially compromised build systems.
What To Do Right Now
Check your lockfiles:
# Search for compromised versions
grep -r "axios@1.14.1\|axios@0.30.4\|plain-crypto-js" package-lock.json yarn.lock
If you find a match — treat the machine as fully compromised. Don’t try to clean it. The RAT’s anti-forensic capabilities mean you can’t trust what’s on disk.
- Rotate every credential on the affected system. SSH keys, cloud tokens, API keys, database passwords, npm tokens, all of it.
- Rebuild from a known-clean image. Don’t patch. Rebuild.
- Audit CI/CD pipelines for runs that installed the affected versions. Those build environments need the same treatment.
- Block egress traffic to
sfrclak[.]comand142.11.206.73at your network perimeter. - Downgrade axios to 1.14.0 (latest safe) or 0.30.3 (legacy safe).
If you’re clean but want to harden against future attacks:
# Run npm install without executing lifecycle scripts
npm install --ignore-scripts
# Or set it globally for CI
npm config set ignore-scripts true
This would have blocked the attack entirely. The tradeoff: some legitimate packages need postinstall hooks (node-sass, sharp, esbuild). You’ll need to whitelist those explicitly or run their scripts manually.
The Bigger Problem
Axios is the most popular HTTP client in JavaScript. One compromised maintainer token (not even a password, a token) gave attackers the ability to push arbitrary code to every project that depends on it.
npm’s security model assumes maintainers keep their credentials safe. When they don’t (or can’t), there’s no secondary gate. The package goes out, postinstall hooks execute automatically, and by the time anyone notices, the malware has already cleaned up its own traces.
This is the third major npm supply chain attack in two weeks, following LiteLLM and Trivy. Combined with AI coding tools doubling secret leak rates, the JavaScript supply chain is having a rough month. All three targeted developer infrastructure. The goal isn’t to break your website. It’s to steal the keys to everything you build and deploy.
npm still hasn’t shipped mandatory 2FA for packages above a download threshold, postinstall hook sandboxing, or publish-time code diffing against the public repository. People have been asking for years. After this week, ignoring those requests gets a lot harder.
FAQ
Was any axios source code modified?
No. The attacker only added a dependency to package.json. All of axios’s actual source files were untouched. The malicious code lived entirely in plain-crypto-js.
How do I know if my machine was infected?
Check your lockfile for axios@1.14.1, axios@0.30.4, or plain-crypto-js@4.2.1. The RAT itself is hard to detect because the dropper deletes its traces. Look for outbound connections to sfrclak[.]com or 142.11.206.73 in your network logs. A hardcoded IE8/Windows XP User-Agent string in outbound HTTP traffic is another strong indicator.
Does npm audit catch this?
Not reliably after the fact. The malicious versions have been removed from npm, so new installs won’t pull them. But npm audit inspects the registry — it can’t tell you whether a RAT already executed on your system during the three-hour window.
Are other axios versions safe?
Yes. Versions 1.14.0 and 0.30.3 are clean. Only 1.14.1 and 0.30.4 were compromised.
Could this happen to other popular packages?
Absolutely. Any npm package where a maintainer uses a classic (non-granular) access token without 2FA is vulnerable to the same attack. The bigger the package, the bigger the payoff.
Bottom Line
A North Korean hacking group owned one npm token and, within 39 minutes, had a cross-platform RAT sitting in the dependency tree of the most popular HTTP library in JavaScript. The malware erased its own footprints. Three hours later it was gone from npm, but the damage was already spreading through CI pipelines and developer machines worldwide.
Check your lockfiles. If you’re hit, burn the machine and rotate everything. And maybe it’s time to start running --ignore-scripts by default — the convenience of automatic postinstall hooks isn’t worth this kind of risk.
