Incident Report: Axios npm Supply Chain Attack — Immediate Actions & Full Analysis
March 31, 2026 • Incident Report, Supply Chain Security, npm, JavaScript
🔴 SEVERITY: CRITICAL — On March 30-31, 2026, the axios npm package (300M+ weekly downloads) was compromised through a hijacked maintainer account. Malicious versions 1.14.1 and 0.30.4 deploy a cross-platform Remote Access Trojan (RAT) targeting SSH keys, AWS credentials, and system access. If you use axios, read this now.
🚨 Immediate Actions (Do This First)
Before investigating whether you're affected, contain the threat. These steps take minutes and prevent active exfiltration.
1. Block Outbound Traffic to C2 Infrastructure
The RAT communicates with a command-and-control server. Block it at your firewall, DNS, or security group level immediately:
# Block at iptables level (Linux)
sudo iptables -A OUTPUT -d 142.11.206.73 -j DROP
sudo iptables -A OUTPUT -d sfrclak.com -j DROP
# Block at DNS level (add to /etc/hosts or DNS blocklist)
echo "0.0.0.0 sfrclak.com" | sudo tee -a /etc/hosts
# AWS Security Group — deny outbound to C2 IP
aws ec2 revoke-security-group-egress --group-id sg-xxxxx --protocol tcp --port 8000 --cidr 142.11.206.73/32
# If using pfSense, Cloudflare Gateway, or corporate firewall:
# Block domain: sfrclak.com
# Block IP: 142.11.206.73
# Block port: 8000
C2 Details:
- Domain: sfrclak.com
- IP: 142.11.206.73
- Port: 8000
- Endpoint: /6202033
2. Check for RAT File Artifacts
The malware drops platform-specific payloads. Check every machine that has run npm install with a potentially compromised axios version:
# macOS — checks for fake Apple daemon
ls -la /Library/Caches/com.apple.act.mond 2>/dev/null && echo "⚠️ INFECTED" || echo "✅ Clean"
# Linux — checks for Python RAT dropper
ls -la /tmp/ld.py 2>/dev/null && echo "⚠️ INFECTED" || echo "✅ Clean"
# Windows (PowerShell)
# Test-Path "$env:PROGRAMDATA\wt.exe" — checks for PowerShell disguised as Windows Terminal
# Test-Path "$env:TEMP\6202033.ps1" — checks for RAT script
3. Kill Active RAT Processes
If you found artifacts above, kill the processes immediately:
# macOS
pkill -f "com.apple.act.mond"
rm -f /Library/Caches/com.apple.act.mond
# Linux
pkill -f "ld.py"
rm -f /tmp/ld.py
# Windows (PowerShell)
# Stop-Process -Name "wt" -Force -ErrorAction SilentlyContinue
# Remove-Item "$env:PROGRAMDATA\wt.exe" -Force
# Remove-Item "$env:TEMP\6202033.ps1" -Force
4. Pin axios to Safe Versions
Add overrides to your package.json to prevent resolution to compromised versions:
{
"overrides": {
"axios": "1.14.0"
}
}
Or for Yarn:
{
"resolutions": {
"axios": "1.14.0"
}
}
Safe versions: [email protected] or [email protected]
5. Disable postinstall Hooks in CI/CD
Prevent any future postinstall-based attacks from executing in your pipelines:
# Use --ignore-scripts for all npm installs in CI
npm ci --ignore-scripts
# Or set globally for CI environments
npm config set ignore-scripts true
🔍 Am I Affected?
Now that you've contained the immediate threat, check whether the compromised versions entered your project.
Check Your Lockfile
# npm — search package-lock.json
grep -E "axios.*1\.14\.1|axios.*0\.30\.4|plain-crypto-js" package-lock.json
# yarn — search yarn.lock
grep -E "axios@.*1\.14\.1|axios@.*0\.30\.4|plain-crypto-js" yarn.lock
# pnpm — search pnpm-lock.yaml
grep -E "axios.*1\.14\.1|axios.*0\.30\.4|plain-crypto-js" pnpm-lock.yaml
Check node_modules
The malicious dependency leaves a trace even after self-cleanup:
# If this directory exists, you were compromised
ls -la node_modules/plain-crypto-js/ 2>/dev/null && echo "⚠️ COMPROMISED — plain-crypto-js found" || echo "✅ Not found"
# Check installed axios version
npm ls axios 2>/dev/null | grep axios
Verify Package Integrity
Compare shasums against known-malicious versions:
# Check your cached axios package
npm cache ls axios 2>/dev/null | grep -E "1\.14\.1|0\.30\.4"
Known malicious shasums:
- [email protected]: 2553649f232204966871cea80a5d0d6adc700ca
- [email protected]: d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71
- [email protected]: 07d889e2dadce6f3910dcbc253317d28ca61c766
If You're Affected: Credential Rotation
If you confirmed compromise, assume all credentials on the machine are stolen:
# Rotate SSH keys
ssh-keygen -t ed25519 -C "rotated-$(date +%Y%m%d)"
# Update authorized_keys on all servers
# Rotate AWS credentials
aws iam create-access-key --user-name YOUR_USER
aws iam delete-access-key --user-name YOUR_USER --access-key-id OLD_KEY_ID
# Rotate npm tokens
npm token revoke <token>
npm token create
# Rotate any other credentials stored in ~/.ssh, ~/.aws, environment variables
Important: The RAT specifically targets
.sshand.awsdirectories for exfiltration. Treat any keys on a compromised machine as burned.
📋 What Happened — Incident Timeline
The attack was staged over 18 hours with surgical precision:
| Time (UTC) | Event |
|---|---|
| Mar 30, 05:57 | Attacker publishes [email protected] — a clean copy of crypto-js to establish publishing history |
| Mar 30, 23:59 | Malicious [email protected] published with obfuscated postinstall hook |
| Mar 31, 00:05 | Socket.dev scanner detects malware — 6-minute detection window |
| Mar 31, 00:21 | [email protected] published with plain-crypto-js injected as dependency |
| Mar 31, 01:00 | [email protected] published — hitting both major version branches (39 min gap) |
| Mar 31, ~03:15 | npm unpublishes both compromised axios versions |
| Mar 31, 04:26 | Security stub replaces malicious package on npm |
Total exposure window: ~3 hours for [email protected], ~2 hours for [email protected]
🔑 How the Account Was Hijacked
The attacker obtained a long-lived classic npm access token belonging to jasonsaayman, the primary axios maintainer. With this token, they:
- Changed the account email to
[email protected](anonymous ProtonMail) - Published directly via npm CLI, bypassing the GitHub Actions CI/CD pipeline entirely
- Avoided OIDC protections — legitimate axios releases use ephemeral tokens scoped to specific GitHub Actions workflows. The stolen classic token had no such restrictions.
The malicious versions have no gitHead references and no corresponding commits or tags in the axios GitHub repository — a clear indicator of out-of-band publishing.
According to axios collaborators, they initially "could not revoke access from the account responsible" because "the attacker's permissions exceed their own." This highlights a critical gap in npm's permission model.
Key takeaway: A single long-lived npm token, combined with npm's "trusted publishing" gaps, gave the attacker full control over a package downloaded 300 million times per week.
🎭 The Decoy Technique — Two-Stage Attack
The attacker didn't just publish malware — they established credibility first.
Stage 1 — The Clean Decoy (05:57 UTC):
[email protected] was published as a functionally clean copy of the legitimate crypto-js library. It had matching descriptions, author attribution, and repository links pointing to the authentic github.com/brix/crypto-js. When automated scanners analyzed the account, it appeared to be a legitimate maintainer with existing publishing history.
Stage 2 — The Malicious Payload (23:59 UTC):
18 hours later, [email protected] arrived with an added postinstall hook in package.json pointing to setup.js — the actual malware dropper.
This two-stage approach is increasingly common in supply chain attacks. By publishing a clean version first, the attacker: - Bypasses "new publisher" heuristics in security scanners - Establishes a version history that looks legitimate - Creates a window where the package appears safe if manually reviewed
💀 Payload Analysis — The Obfuscation & RAT
Dependency Injection
The compromised axios versions added plain-crypto-js@^4.2.1 as a runtime dependency. Critically, this package is never imported or required anywhere in axios's 86 source files. It exists solely to trigger the postinstall hook during npm install.
Two-Layer Obfuscation
The setup.js dropper uses a custom encoding scheme to evade static analysis:
Layer 1 — XOR Cipher (_trans_1):
// Key: "OrDeR_7077" — only digits survive bitwise ops
// Effective key digits: [0, 0, 0, 0, 0, 0, 7, 0, 7, 7]
// Decode: charCode XOR key[(7 * r * r) % 10] XOR 333
Layer 2 — Reversed Base64 (_trans_2):
Strings are reversed, underscores replaced with = padding, base64-decoded, then fed through the XOR cipher.
The 18 decoded strings reveal the attack surface:
"child_process", "os", "fs" → System access modules
"http://sfrclak.com:8000/" → C2 server
"win32", "darwin" → Platform detection
"/Library/Caches/com.apple.act.mond" → macOS payload path
"%PROGRAMDATA%\\wt.exe" → Windows payload path
"/tmp/ld.py" → Linux payload path
Platform-Specific RAT Delivery
macOS:
- Downloads Mach-O binary to /Library/Caches/com.apple.act.mond — mimicking legitimate Apple daemon naming (com.apple.*)
- Executes via /bin/zsh in background
- RAT capabilities: Command execution, binary injection with code signing, AppleScript execution, directory enumeration (.ssh, .aws), process listing
- Beacons to C2 every 60 seconds with a fake User-Agent: "mozilla/4.0 (compatible; msie 8.0; windows nt 5.1; trident/4.0)" (IE8 on XP — intentionally archaic)
- Generates unique 16-character victim ID; fingerprints hostname, username, macOS version, timezone, CPU, install date, boot time
Windows:
- Three-stage execution chain: PowerShell → copies itself to %PROGRAMDATA%\wt.exe (disguised as Windows Terminal for EDR evasion) → VBScript downloads .ps1 to %TEMP%\6202033.ps1 → executes with -WindowStyle Hidden -ExecutionPolicy Bypass
- VBS self-deletes after execution
Linux:
- Simplest variant: curl downloads Python script to /tmp/ld.py
- Executes detached with nohup python3 /tmp/ld.py > /dev/null 2>&1 &
- Background process orphaned (ppid: 1) to survive terminal closure
🕵️ Anti-Forensics — Covering Tracks
After payload delivery, the dropper executes a three-step evidence destruction sequence:
// 1. Delete the malicious script itself
fs.unlink(__filename) // removes setup.js
// 2. Delete the incriminating package.json (contains postinstall hook)
fs.unlink('package.json')
// 3. Rename pre-staged clean stub to package.json
fs.rename('package.md', 'package.json')
Post-infection, the plain-crypto-js directory looks like an ordinary crypto-js copy — no postinstall scripts, no traces. However, the directory's mere existence proves compromise since plain-crypto-js is not a legitimate axios dependency.
C2 Traffic Disguise
The RAT disguises its POST requests to mimic npm registry traffic:
- POST bodies reference packages.npm.org/product0|1|2 (distinguishing macOS/Windows/Linux)
- Note: the legitimate npm registry is registry.npmjs.org — the attacker used npm.org which belongs to the National Association of Pastoral Musicians (registered since 1997)
🛡️ Indicators of Compromise (IOCs)
Affected Packages
| Package | Version | SHA |
|---|---|---|
axios |
1.14.1 |
2553649f232204966871cea80a5d0d6adc700ca |
axios |
0.30.4 |
d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71 |
plain-crypto-js |
4.2.1 |
07d889e2dadce6f3910dcbc253317d28ca61c766 |
@shadanai/openclaw |
2026.3.31-1, 2026.3.31-2 |
Cascade victims |
@qqbrowser/openclaw-qbot |
0.0.130 |
Cascade victim |
Network Indicators
| Indicator | Value |
|---|---|
| C2 Domain | sfrclak.com |
| C2 IP | 142.11.206.73 |
| C2 Port | 8000 |
| C2 Endpoint | /6202033 |
| Platform endpoints | /product0 (macOS), /product1 (Windows), /product2 (Linux) |
| Fake User-Agent | mozilla/4.0 (compatible; msie 8.0; windows nt 5.1; trident/4.0) |
File Artifacts
| Platform | Path | Description |
|---|---|---|
| macOS | /Library/Caches/com.apple.act.mond |
Mach-O RAT binary |
| Windows | %PROGRAMDATA%\wt.exe |
PowerShell copy disguised as Windows Terminal |
| Windows | %TEMP%\6202033.ps1 |
RAT PowerShell script |
| Windows | %TEMP%\6202033.vbs |
VBScript launcher (self-deletes) |
| Linux | /tmp/ld.py |
Python RAT script |
📝 Lessons & Prevention
For Package Maintainers
- Eliminate long-lived npm tokens. Use npm's granular access tokens with IP restrictions and expiration dates. Better yet, use OIDC-based trusted publishing tied to your CI/CD pipeline.
- Enable npm 2FA for publishing. This single step would have prevented the attacker from publishing with a stolen token.
- Monitor account email changes. npm should notify all collaborators when a maintainer's email is changed — not just the (compromised) account holder.
For Developers & Teams
- Use
npm ci --ignore-scriptsin CI/CD. This blockspostinstallhooks — the primary attack vector for npm supply chain attacks. Selectively allow scripts only for packages that genuinely need them. - Pin exact versions in lockfiles. Don't use
^or~ranges for critical dependencies in production. Usenpm shrinkwrapor committed lockfiles. - Audit dependencies with automated tools. Socket.dev, Snyk, and npm audit can catch malicious packages — Socket detected this attack in 6 minutes.
- Monitor for unexpected dependencies. A dependency appearing that has no
import/requirein source code is a red flag. Consider tools that check for phantom dependencies. - Implement egress filtering. Block all outbound traffic from CI/CD runners and production servers except known-good destinations. This would have prevented the RAT from reaching its C2.
For the npm Ecosystem
This attack is the latest in a growing pattern: event-stream (2018), ua-parser-js (2021), colors/faker (2022), and now axios (2026). The common thread is account compromise + postinstall hooks. The ecosystem needs:
- Mandatory 2FA for high-download packages (npm has been rolling this out, but adoption is still incomplete)
- Publish provenance verification — reject packages that bypass CI/CD attestation
- Postinstall hook transparency — flag and require explicit user consent for packages with install scripts
Attribution Notes
The attack shows hallmarks of an Advanced Persistent Threat (APT) rather than a typical financially motivated actor:
- No crypto miners or ransomware deployed
- Focus on reconnaissance:
.sshand.awscredential harvesting - Sophisticated anti-forensics and multi-platform support
- Carefully staged over 18 hours with decoy technique
- Intelligence-gathering behavior patterns
References
- Socket.dev — Axios npm Package Compromised
- StepSecurity — Axios Compromised on npm: Malicious Versions Drop Remote Access Trojan
- ITNews — Supply Chain Attack Hits 300 Million Download Axios npm Package
Responsible Disclosure
This incident report is based on publicly available information from security researchers at Socket.dev and StepSecurity. The compromised packages have been removed from npm. This post is intended to help developers assess their exposure and take protective action.
Stay safe out there. If you have questions or need help assessing your exposure, reach out on Twitter/X.