Three hours was the good outcome: npm's trust model and the Axios compromise
A DPRK threat actor backdoored two Axios versions on npm. Socket flagged the malicious dependency in six minutes. Nothing stopped the downstream publish fifteen minutes later. The system worked exactly as designed.
On March 31, 2026, a North Korean state-sponsored threat actor published two backdoored versions of Axios, the HTTP client library with roughly 100 million weekly downloads and 174,121 dependent packages on npm. The malicious versions were live for two hours and 54 minutes before the community detected the compromise and npm pulled them. Socket’s automated scanner flagged the injected dependency within six minutes of publication.
Three hours of exposure across a library that underpins a measurable fraction of the JavaScript ecosystem. And that was the fast version. The system has no architectural protection against a slower, quieter attacker who doesn’t trip the obvious signals.
What one npm account buys you
Sapphire Sleet, the DPRK-linked group Microsoft tracks (Google calls them UNC1069), spent weeks on this operation. They didn’t find a zero-day. They didn’t compromise npm’s infrastructure. They social-engineered one person.
The attacker posed as the founder of a legitimate company, built a fake Slack workspace populated with fake employee profiles and other open-source maintainer identities, and invited the lead Axios maintainer to what looked like a professional collaboration. During a Teams meeting, a fabricated error prompted the maintainer to install what appeared to be a “Teams update.” It was a remote access trojan. That gave the attacker access to authenticated npm sessions, bypassing MFA entirely.
This is the same group linked to the Bangladesh Bank SWIFT heist in 2016 ($81 million), the Ronin Network bridge breach in 2022 (roughly $617 million), and over $10 million in cryptocurrency theft in a six-month period ending early 2026. They invested weeks of social engineering infrastructure for access to one npm account. Because one npm account was sufficient.
Multiple other open-source maintainers, including Mocha’s maintainer, reported similar targeting during the same period.
The six-minute gap that didn’t matter
Here is the timeline that should bother you.
The attacker pre-seeded a clean version of their malicious dependency, [email protected], on March 30 to establish publishing history. The backdoored 4.2.1 went up at 23:59 UTC that same day. Socket’s automated detection flagged it within six minutes.
Fifteen minutes after that flag, the attacker published [email protected] with [email protected] as a dependency. Thirty-nine minutes later, [email protected] followed on the legacy branch. Socket had already flagged the dependency as malicious. It did not matter. No circuit breaker exists between “dependency flagged as malicious” and “package depending on it can still be published.”
The detection worked. The architecture around the detection did not.
Community members filed GitHub issues on the Axios repository. The attacker deleted them using the compromised maintainer account. A collaborator named DigitalBrainJS contacted npm directly. The malicious versions were pulled by 03:15 UTC. Total exposure: about three hours.
What ran on your machine
The backdoored Axios versions added [email protected] to package.json. No source files were modified. The attack is notable for its restraint.
The malicious package used a postinstall hook to deploy a cross-platform RAT. On Windows, a PowerShell-based trojan persisted via the registry Run key (HKCU:\Software\Microsoft\Windows\CurrentVersion\Run\MicrosoftUpdate), though an implementation bug meant it never called its main function on first run, only activating after reboot. On macOS, a universal Mach-O binary landed at /Library/Caches/com.apple.act.mond (Google’s Mandiant team identified this as WAVESHAPER.V2, attributed to UNC1069). On Linux, a Python loader dropped to /tmp/ld.py, which crashed in containers due to os.getlogin() failing without a TTY.
Anti-forensics were minimal but effective: the dropper deleted itself within 15 seconds, leaving clean-looking node_modules.
The implementation bugs are not reassuring. They mean this particular payload was imperfect. They do not mean the delivery mechanism was.
The trust model that made this work
Four properties of npm’s ecosystem combined to make this attack viable at scale.
Postinstall hooks execute arbitrary code with no sandboxing. When you run npm install, any package in the dependency tree can run any command on your machine. That’s the documented behavior. The backdoored Axios versions used this to deploy a RAT. The same mechanism is used by thousands of legitimate packages for build steps. There is no distinction between the two at the platform level.
Semver ranges amplify a single malicious publish. Most package.json entries use the ^ prefix, which accepts any minor or patch version bump automatically. A single malicious publish propagates through semver resolution to every downstream consumer that runs npm install before the package is pulled. With 174,121 dependent packages, the blast radius of a three-hour window is not trivial.
Single-maintainer risk is structural. Axios has a small maintainer team. The attacker needed to compromise one authenticated session. There is no review gate, no second-person approval, no cooling period between publishing a version of a package with 100 million weekly downloads and that version being installable worldwide.
Detection and prevention are decoupled. Socket flagged the malicious dependency in six minutes. That detection produced no automated response. The downstream publish happened anyway. The gap between detection and enforcement is filled entirely by human intervention: filing issues, contacting npm support, waiting.
The escalation pattern
This is not the first npm supply chain compromise. But the trajectory is worth sitting with.
In 2018, the event-stream backdoor involved social transfer of maintainership, targeted cryptocurrency wallets, and went undetected for months. In 2021, ua-parser-js (7 million weekly downloads) was compromised via account takeover and caught in hours. In 2022, the colors.js maintainer sabotaged their own package (roughly 20 million weekly downloads) in a protest that persisted for days.
Axios in 2026: 100 million weekly downloads, state-sponsored social engineering, approximately three hours of exposure. The scale keeps growing. The sophistication keeps growing. The detection keeps getting faster. And the architectural defenses remain the same.
What to do
If you haven’t already checked, do it now.
Search your lockfiles for [email protected] or [email protected]. Run npm ls plain-crypto-js. Check host artifacts: on macOS, look for /Library/Caches/com.apple.act.mond; on Windows, check for %PROGRAMDATA%\wt.exe and the registry key at HKCU:\Software\Microsoft\Windows\CurrentVersion\Run\MicrosoftUpdate; on Linux, check /tmp/ld.py.
If you find any of these: assume breach. Isolate the affected systems, rotate all secrets, rebuild from clean snapshots, and audit your CI/CD pipelines. Google noted that “hundreds of thousands of stolen secrets could potentially be circulating.” eSentire detected 19 affected customers across their base. Unit 42 found impact across 10 industry sectors. EMEA was disproportionately affected due to the timezone of the exposure window.
For prevention going forward: pin exact dependency versions, use npm ci --ignore-scripts in CI pipelines, commit your lockfiles, and look at OIDC-based publishing which ties publishes to CI provenance rather than long-lived tokens.
The uncomfortable part
CISA issued an advisory on April 20, three weeks after the compromise. The community caught it in three hours. The detection tooling caught the signal in six minutes. And still, no automated mechanism prevented the downstream publish.
The system worked as well as it possibly could within its current design. A nation-state with the resources to stage weeks of social engineering, build fake corporate infrastructure, and target individual maintainers got roughly three hours of access to the npm ecosystem’s most-downloaded HTTP client. That’s a good outcome by every historical comparison.
It is also a system where “good outcome” means “we only exposed 174,000 dependent packages to a state-sponsored RAT for the duration of a long lunch.” PatchDay Alert covers supply chain events like this in the daily digest, including the specific version numbers and host artifacts you need to check.
The next attacker will study what tripped the detection and adjust. The question is whether npm’s architecture will adjust first.
Sources
- Microsoft Security Blog: Mitigating the Axios npm supply chain compromise
- GitHub Issue #10636: Post Mortem
- Google Cloud Blog: North Korea-Nexus Threat Actor Compromises Axios NPM Package
- Socket.dev: Supply Chain Attack on Axios
- Elastic Security Labs: Inside the Axios supply chain compromise
- BleepingComputer: Axios npm hack used fake Teams error fix to hijack maintainer account
Share
Related field notes
-
50 CVEs in 18 months is not a growing pain. It's a design choice the industry keeps making.
MCP went from unknown to default AI integration in under two years. The vulnerability count, the OWASP Top 10, and the simultaneous client failures tell a story about what happens when adoption is the only metric.
-
Spirit Airlines is dead. Its attack surface isn't.
The security story isn't that an airline went bankrupt. It's what happens to 132 APIs, years of customer PII, and a cloud footprint when a company dies overnight and nobody is left to decommission it.
-
The Vercel breach is the Heroku/Travis CI playbook, rerun through an AI tool
A compromised OAuth token at a small AI productivity company gave attackers a path into Vercel's internal systems. The structural pattern is four years old. AI tools are making it worse.