Safeguard
Software Supply Chain Security

Axios npm package RAT supply chain compromise

A compromised maintainer account pushed malicious axios releases carrying a cross-platform RAT to npm on March 31, 2026 — here's the full timeline and IOCs.

Safeguard Research Team
Research
7 min read

On March 31, 2026, at 00:21 UTC, npm accepted a new release of axios — version 1.14.1 — signed by a compromised maintainer account. Twenty-three minutes later, a second poisoned release, 0.30.4, followed. Both versions silently pulled in a fake dependency called plain-crypto-js, a package that axios never actually imports anywhere in its source. That dependency's postinstall script downloaded an obfuscated dropper, fingerprinted the host OS, and deployed a cross-platform remote access trojan with separate builds for Windows, macOS, and Linux. axios ships more than 100 million weekly downloads and sits underneath roughly 174,000 dependent npm packages, so a three-hour exposure window translated into a very large blast radius before anyone even knew there was a fire. Microsoft has since attributed the campaign to Sapphire Sleet, a North Korean state-sponsored actor with a track record of targeting developers directly. Here is what actually happened, and what to check on your own systems.

What happened in the axios npm supply chain attack?

Attackers published two malicious axios releases, 1.14.1 and 0.30.4, that installed a remote access trojan on any machine that ran npm install during a roughly three-hour window on March 31, 2026. The compromised versions did not modify axios's own 85 library files — a binary diff later showed only package.json had changed, which is exactly what made the tampering easy to miss in a quick review. Instead, the attackers added a single new line to the dependency tree: plain-crypto-js@4.2.1, a package with a legitimate-sounding name and a clean-looking prior release (4.2.0, published the day before on March 30 at 05:57 UTC) to pass casual scrutiny. The malicious 4.2.1 version carried a postinstall script that fetched and executed setup.js, an obfuscated loader whose SHA-256 hash (e10b1fa8...4c2e0e09) has since been published as an IOC by multiple vendors. setup.js detected the operating system and pulled the matching second-stage payload — one RAT per platform, all speaking the same command-and-control protocol.

How did attackers gain access to publish malicious axios versions?

Attackers compromised the npm account of axios lead maintainer jasonsaayman through a targeted social engineering campaign that had reportedly been running for roughly two weeks before the malicious publish. The campaign culminated in a RAT infection on the maintainer's own machine, which gave the attackers access to his local credentials and publishing tokens. As part of taking over the account, the attacker changed the registered account email from jasonsaayman@gmail.com to an attacker-controlled address, ifstap@proton.me, and a second attacker-linked account, nrwise (nrwise@proton.me), was also involved in the operation. This is the same pattern that has now hit several high-profile npm maintainers in the last two years: attackers do not bother trying to break npm's infrastructure, they go after the human with publish rights, because one stolen token is worth more than any zero-day. In axios's post-incident writeup, the maintainers noted plainly that "the attacker gained access to the lead maintainer's PC through a targeted social engineering campaign and RAT malware" — the very same malware class the attackers then redistributed to axios's own downstream users.

What did the malicious packages actually install?

The malicious packages installed an OS-specific remote access trojan that phoned home to a command-and-control server at sfrclak.com over port 8000, exfiltrating local system and user data. Once setup.js identified the platform, it dropped persistence artifacts that differed by OS: a hidden wt.exe binary under %PROGRAMDATA% plus a VBScript/PowerShell pair (6202033.vbs, 6202033.ps1) in %TEMP% on Windows, a disguised file at /Library/Caches/com.apple.act.mond on macOS, and a Python script at /tmp/ld.py on Linux. Each variant beaconed to the same C2 infrastructure — resolving to IP 142.11.206.73 — and POSTed stolen data back tagged by platform (product0 for macOS, product1 for Windows, product2 for Linux), which tells you this was built as one coordinated toolkit rather than three separate one-off scripts. After deployment, the dropper attempted to erase its own tracks and replace its package.json with a clean-looking decoy, a detail that matters for incident responders: a live filesystem check after the fact may not show the dropper file itself, only its downstream persistence artifacts.

Who was affected, and for how long were the packages live?

Any project that resolved a fresh install of axios@1.14.1 or axios@0.30.4 between 00:21 UTC and roughly 03:15–03:25 UTC on March 31, 2026 pulled the malicious code, and given axios's 174,000 dependent packages and 100+ million weekly downloads, the exposure window overlapped with an enormous volume of CI runs, container builds, and developer machines worldwide. npm removed the malicious axios versions at approximately 03:15 UTC and placed a security hold on plain-crypto-js at 03:25 UTC, publishing a stub replacement about an hour later at 04:26 UTC. That's roughly a three-hour window from first malicious publish to takedown — short by the standards of some historic incidents (the event-stream compromise ran undetected for months in 2018), but long enough to matter given axios's install volume: any automated dependency bump, nightly build, or npm ci running against an unpinned axios range during that window would have resolved to the poisoned version without any human in the loop noticing.

How should teams detect and remediate exposure now?

Teams should first check whether any build, container image, or lockfile resolved axios to 1.14.1 or 0.30.4, or pulled plain-crypto-js@4.2.1 at all, since that package is never legitimately imported by axios and its mere presence is itself a compromise indicator. Compare your installed axios shasum against the known-clean 1.14.0 (7c29f4cf...ed3120eb) or 0.30.3 release, and pin to those or later patched versions going forward rather than trusting caret ranges on a package this central to your dependency graph. Search affected hosts for the platform-specific artifacts described above — wt.exe under %PROGRAMDATA%, the 6202033.vbs/6202033.ps1 pair in %TEMP%, /Library/Caches/com.apple.act.mond on macOS, or /tmp/ld.py on Linux — and block outbound traffic to sfrclak.com and 142.11.206.73:8000 at the network layer regardless of whether you find local artifacts, since the dropper is designed to self-delete. Notably, there was no automated detection inside npm itself; the compromise surfaced only because a maintainer collaborator and external researchers (StepSecurity's tooling flagged the anomalous outbound connection to sfrclak.com during a routine CI run) noticed the anomaly and pushed for a takedown within about 80 minutes of the first malicious publish. That's the uncomfortable lesson here: registry-level trust signals like OIDC-based publishing and immutable releases — both of which axios adopted only after this incident — are controls organizations should be verifying in their own critical dependencies today, not waiting to add after their own maintainer gets phished.

How Safeguard Helps

Incidents like this expose the limits of scanning a manifest file and calling it a day — the malicious change here was a single, unimported line in a lockfile, and most teams don't have visibility into whether a compromised transitive dependency is even reachable from code that actually runs. Safeguard's reachability analysis traces whether a package like plain-crypto-js is invoked anywhere in your call graph, so you can immediately separate "this touched our build" from "this touched our production runtime" instead of treating every dependent package as equally urgent. Griffin AI continuously watches for exactly this pattern — phantom dependencies, unexpected postinstall scripts, and version publishes that don't correspond to a signed commit or tag — and flags them before a routine npm install pulls them into a build. Because Safeguard generates and ingests SBOMs across your fleet, you can query in minutes whether any service ever resolved axios@1.14.1, axios@0.30.4, or plain-crypto-js@4.2.1, rather than grepping lockfiles repo by repo during an active incident. And once a fix is available, Safeguard opens auto-fix pull requests that pin affected projects to the verified-clean axios release, so remediation ships at the same speed the compromise spread.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.