StepSecurity identified and published a full technical breakdown of a supply chain attack against axios on March 30. Malwarebytes picked it up the next day. I came across the Malwarebytes report first, then went back to read StepSecurity’s analysis — then checked whether this site is exposed. Axios is the most downloaded JavaScript HTTP client on npm, around 100 million weekly downloads.
What Happened
A compromised maintainer account was used to push two malicious axios versions to npm: axios@1.14.1 and axios@0.30.4. Neither version exists in the axios GitHub repository — no commits, no tags. The attack happened entirely at the npm registry level.
Both versions were live for under three hours on March 31 before npm took them down. The window was short, but exposure wasn’t limited to developers who explicitly installed axios — anyone who ran npm install with either version already in their package.json, or with a dependency that pulled axios transitively, got the poisoned package.
The injection was precise: the only difference between the clean and malicious releases was the addition of a single hidden dependency called plain-crypto-js — a package that doesn’t exist anywhere in the real axios source code. Its only job was to run a script at install time.
What the Attack Does
When you install the compromised axios, plain-crypto-js runs automatically as part of the install process. It contacts a command-and-control server (sfrclak.com) and downloads a Remote Access Trojan specific to your operating system — macOS, Windows, or Linux. After delivering the payload, the malicious script erases itself and replaces its own metadata with a clean-looking file to avoid detection.
Warning
This means running npm audit after the fact shows nothing suspicious. The evidence is gone. If the install happened, assume the machine is compromised.
The attack was also pre-planned: 18 hours before the poisoned axios versions went live, the attacker published a clean, innocent-looking version of plain-crypto-js to establish account history — specifically to avoid “brand new package” alarms from security scanners. The malicious version followed later that night, minutes before the axios releases.
Checking This Project
This site runs on Astro and doesn’t use axios. But “not in my package.json” isn’t enough — a dependency of a dependency can pull it in without you knowing. I ran four checks:
npm ls axios# astro-erudite@1.6.3# └── (empty)
grep -i "axios" package-lock.json# (no output)
ls node_modules/plain-crypto-js# NOT FOUND
ls -la /Library/Caches/com.apple.act.mond# NOT FOUNDAxios isn’t present anywhere in the dependency tree or lockfile. The plain-crypto-js directory doesn’t exist. The macOS RAT artifact isn’t on this machine. I also ran npm audit — 5 moderate vulnerabilities unrelated to this incident, zero mentions of axios or plain-crypto-js.
That folder check matters more than the version number, because the malware replaces its own package.json with a clean decoy after running — so npm list will show 4.2.0 instead of the malicious 4.2.1. If the directory exists at all, the dropper ran.
What to Do If You Use Axios
Check which version you have installed. The affected versions are 1.14.1 and 0.30.4. If you’re on either, or if you ran any npm install on March 31 between 00:21 and 03:15 UTC with axios anywhere in your dependency tree, treat the machine as compromised.
The persistent files left behind by the RAT differ by platform:
- macOS —
/Library/Caches/com.apple.act.mond - Linux —
/tmp/ld.py - Windows (persistent) —
%PROGRAMDATA%\wt.exe - Windows (temp, self-deletes) —
%TEMP%\6202033.vbs,%TEMP%\6202033.ps1
If any of those exist on a machine where axios was recently installed, rotate every credential that was accessible on that machine: npm tokens, SSH keys, cloud credentials, API keys, anything stored or loaded in the shell environment.
Warning
Don’t try to clean in place. Reformat and rebuild from a known-good state, then rotate secrets from a separate clean machine.
Indicators of Compromise
For incident response or detection tooling. If you use axios and ran npm install on March 31 between 00:21–03:15 UTC, these are the signals to check.
Packages — malicious vs safe
| Package | Version | SHA1 | Status |
|---|---|---|---|
axios | 1.14.1 | 2553649f2322049666871cea80a5d0d6adc700ca | malicious |
axios | 0.30.4 | d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71 | malicious |
plain-crypto-js | 4.2.1 | 07d889e2dadce6f3910dcbc253317d28ca61c766 | malicious |
axios | 1.14.0 | 7c29f4cf2ea91ef05018d5aa5399bf23ed3120eb | safe |
Network
C2 domain sfrclak.com · IP 142.11.206.73 · URL http://sfrclak.com:8000/6202033
POST body by OS: macOS → packages.npm.org/product0, Windows → product1, Linux → product2
File system artifacts
| Platform | Path |
|---|---|
| macOS | /Library/Caches/com.apple.act.mond |
| Windows (persistent) | %PROGRAMDATA%\wt.exe |
| Windows (temp) | %TEMP%\6202033.vbs, %TEMP%\6202033.ps1 |
| Linux | /tmp/ld.py |
Broader sweep commands
# installs during attack windowgrep -i "npm install" ~/.zsh_history | grep "2026-03-31"
# all lockfiles referencing malicious versionsfind ~ -name "package-lock.json" -exec grep -l "1\.14\.1\|0\.30\.4" {} \;
# active C2 connectionlsof -i | grep sfrclakAttacker accounts
jasonsaayman— compromised axios maintainer; email changed toifstap@proton.menrwise— attacker-created (nrwise@proton.me); publishedplain-crypto-js
The Broader Takeaway
What made this attack harder to catch than most is the preparation. The attacker staged the malicious dependency nearly a day in advance to build a credible history. Both the modern 1.x and legacy 0.x release branches were hit within 39 minutes. And the payload self-destructs, so post-infection inspection looks clean.
The one signal that doesn’t lie is the npm registry metadata: every legitimate axios release is published through GitHub Actions with a verified OIDC token tied to a specific workflow run. The malicious versions were published manually with a stolen account token — no workflow link, no corresponding GitHub commit. That mismatch is checkable for any package before you trust a version.