The Axios Supply Chain Attack: How North Korea Hijacked npm's Most Popular HTTP Client
For two hours on March 31, anyone who ran npm install axios got a North Korean RAT. The real package, the real registry, the real maintainer account — compromised.
On March 31, 2026, someone ran npm install and unknowingly handed their machine to North Korean hackers.
The package was axios — the most popular HTTP client in JavaScript, with over 100 million weekly downloads. For roughly two hours, anyone who installed a fresh copy got a cross-platform remote access trojan delivered straight to their development machine. No typosquat. No lookalike package. The real axios, from the real npm registry, published through the real maintainer account.
This is the story of how it happened, what the malware does, and why the npm ecosystem keeps producing these attacks.
What Happened
Between 00:21 and 03:29 UTC on March 31, two malicious versions of axios appeared on npm: 1.14.1 and 0.30.4. The attacker had compromised the npm account of @jasonsaayman, the primary maintainer, changing the registered email to an attacker-controlled ProtonMail address ([email protected]).
No axios source code was modified. Instead, the attacker added a single dependency to package.json: [email protected]. That package had been uploaded 18 hours earlier — a clean version (4.2.0) published first to build a brief history on the registry and avoid triggering "brand-new package" alerts from security scanners.
When npm install runs, it resolves the dependency tree, pulls [email protected], and automatically executes its postinstall hook: node setup.js. That single line of code is where the compromise begins.
The malicious versions were live for approximately two hours before being pulled. In that window, every CI/CD pipeline, every developer laptop, and every build system that ran a fresh install was potentially compromised.
The Malware: WAVESHAPER.V2
Google Threat Intelligence Group (GTIG) attributes this attack to UNC1069, a financially motivated North Korea-nexus threat actor active since at least 2018. The payload is an updated version of their WAVESHAPER backdoor.
The Dropper
setup.js uses two layers of obfuscation to avoid static analysis:
- Reversed Base64 encoding with padding character substitution
- XOR cipher with the key
OrDeR_7077and a constant value of 333
Once decoded, the script detects the host operating system and contacts the C2 server at sfrclak[.]com:8000 (IP: 142.11.206.73) to download a platform-specific second-stage payload.
After execution, the dropper erases itself. It deletes setup.js, removes the package.json containing the postinstall hook, and replaces it with a clean file renamed from package.md. If you inspect node_modules/plain-crypto-js after the fact, there's no indication anything happened.
Platform-Specific Payloads
macOS: Downloads a Mach-O binary to /Library/Caches/com.apple.act.mond — deliberately mimicking an Apple daemon naming convention. The RAT generates a unique victim ID, fingerprints the system, and beacons to the C2 every 60 seconds using a fake IE8/Windows XP User-Agent string. It accepts four commands: binary injection with ad-hoc code signing to bypass Gatekeeper (peinject), arbitrary shell command execution (runscript), filesystem enumeration (rundir), and self-termination (kill).
Windows: A VBScript copies powershell.exe to %PROGRAMDATA%\wt.exe (disguised as Windows Terminal) and executes a hidden PowerShell RAT with execution policy bypass.
Linux: A Python RAT downloads to /tmp/ld.py and launches as an orphaned background process via nohup python3, detaching from the spawning terminal.
Three payloads. Three operating systems. All pre-built and staged before the attack went live.
The Sophistication Is the Problem
This wasn't a hastily thrown-together attack. Consider the timeline:
| Time (UTC) | Event |
|---|---|
| ~18 hours before | [email protected] published (clean, building registry history) |
| 00:21 Mar 31 | [email protected] published with malicious dependency |
| 01:00 Mar 31 | [email protected] published (second branch poisoned) |
| 03:15 Mar 31 | Malicious versions flagged |
| 03:29 Mar 31 | Removed from npm |
Both release branches were poisoned within 39 minutes of each other. The staging package was pre-seeded. The self-erasing mechanism was built in from the start. Within two seconds of npm install, the malware was already calling home to the attacker's server — before npm had even finished resolving the rest of the dependency tree.
StepSecurity called it "among the most operationally sophisticated supply chain attacks ever documented against a top-10 npm package." That's not hyperbole.
Not an Isolated Incident
The axios attack didn't happen in a vacuum. In the same week:
CVE-2026-4800 exposed a code injection vulnerability in lodash's _.template function — another foundational npm package with 200+ million monthly downloads. The original fix for CVE-2021-23337 in 2021 patched the variable option but left the imports key completely unvalidated. Five years. Same injection class. Different parameter.
And just weeks earlier, researchers discovered multiple malicious packages targeting AI development tools in the npm ecosystem, including packages impersonating OpenClaw and other automation platforms.
The pattern is clear: npm's most trusted packages — the ones that sit in virtually every JavaScript project's dependency tree — are under sustained, coordinated attack.
Why npm Keeps Getting Hit
The fundamental problem isn't technical. It's trust architecture.
npm operates on implicit trust. When you run npm install, you trust that every package in your dependency tree — and every maintainer account behind those packages — hasn't been compromised since the last time you checked. There's no verification of build reproducibility. There's no mandatory 2FA enforcement for critical packages. A single compromised account can push malicious code to millions of machines within minutes.
The axios attack exploited every one of these assumptions:
- Account takeover → No mandatory hardware key 2FA for top packages
- Postinstall hooks → Arbitrary code execution during install, before any developer review
- Implicit dependency trust → Adding a new dependency doesn't trigger any special review
- No build provenance → The published package doesn't need to match any audited source code
npm has introduced some mitigations — mandatory 2FA for packages above certain download thresholds, npm provenance for verified builds. But as this attack proves, the gap between "available" and "enforced" is where attackers operate.
What To Do Right Now
If You Installed During the Window (00:21–03:29 UTC, March 31)
Assume full compromise. The RAT provides remote code execution, filesystem access, and arbitrary command execution. This means:
- Rotate all secrets accessible from the compromised machine — API keys, tokens, SSH keys, credentials
- Check lockfiles for
[email protected],[email protected], or[email protected] - Scan for IOCs:
- C2 domain:
sfrclak[.]com:8000 - C2 IP:
142.11.206.73 - macOS artifact:
/Library/Caches/com.apple.act.mond - Windows artifact:
%PROGRAMDATA%\wt.exe - Linux artifact:
/tmp/ld.py
- C2 domain:
- Audit CI/CD pipelines that ran during the window — especially those with access to production credentials
For Everyone Else
- Pin your dependencies. Use lockfiles (
package-lock.json,yarn.lock,bun.lockb) and commit them - Enable npm provenance where available
- Audit postinstall scripts — consider running
npm install --ignore-scriptsby default and explicitly allowing known hooks - Monitor dependency changes in your projects. A new transitive dependency appearing in a minor version bump is a red flag
- Track your dependencies for security advisories — know when something in your stack gets compromised before it hits your pipeline
The Bigger Picture
The axios attack is a warning shot, not an endpoint. North Korean threat actors are investing in supply chain attacks because the ROI is extraordinary: compromise one account, reach 100 million installations. The two-hour window was enough.
The npm ecosystem powers the internet. When axios is compromised, every application, every API, every microservice that depends on it is potentially affected. The question isn't whether another top-10 package will be targeted — it's when.
The only defense is knowing what's in your dependency tree and being notified the moment something changes. That's not optional anymore. It's operational security.
Track your npm dependencies on VulnTracker. Get notified when packages in your stack are compromised, patched, or flagged — before your next npm install.