[ FIELD_NOTE ]

Axios npm Supply Chain Attack 2026

[supply-chain][npm][malware][apt][javascript]
4_READS·31_MARCH_2026·5_MIN_READ

On March 31, 2026, two malicious versions of axios were published to npm using a stolen maintainer token. Any machine that ran npm install during a three-hour window may have received a cross-platform Remote Access Trojan. Google's Threat Intelligence Group attributed the campaign to UNC1069, a North Korea-nexus APT.

What happened

The attacker compromised the npm account of jasonsaayman, the primary axios maintainer, by obtaining a long-lived classic npm access token. They changed the registered account email to an attacker-controlled ProtonMail address to lock out the rightful owner.

Two malicious versions were published:

| Version | Tag | Published (UTC) | |---|---|---| | axios@1.14.1 | latest | Mar 31 00:21 | | axios@0.30.4 | legacy | Mar 31 01:00 |

Both versions were removed from npm by 03:29 UTC — a window of roughly three hours. During that window, anyone whose CI/CD pipeline or developer machine ran npm install axios resolved to a backdoored release.

How the attack was staged

The operation was pre-staged 18 hours in advance — not opportunistic.

18 hours before: A clean decoy package plain-crypto-js@4.2.0 was published to build a short registry history and avoid new-package alarms.

23:59 UTC (Mar 30): plain-crypto-js@4.2.1 was published. This version contained the malicious postinstall payload — an obfuscated dropper using reversed Base64 encoding and an XOR cipher with the key OrDeR_7077.

00:21 UTC (Mar 31): axios@1.14.1 published with plain-crypto-js@4.2.1 injected as a runtime dependency. Tagged latest.

01:00 UTC: axios@0.30.4 published via the same compromised account. Tagged legacy. Both release branches hit within 39 minutes.

The malicious versions had no OIDC provenance metadata and no SLSA build attestation — they were published directly via token, leaving no verifiable build trail. Legitimate axios releases always include cryptographic binding to a specific GitHub Actions run.

The payload

When npm install ran, the dependency tree pulled plain-crypto-js@4.2.1 automatically. npm then executed its postinstall hook — node setup.js — with no user interaction required.

The dropper contacted the C2 server at sfrclak[.]com:8000 (IP: 142.11.206.73), detected the host operating system, and downloaded a platform-specific stage-2 RAT:

| Platform | Implementation | Artifact path | |---|---|---| | macOS | C++ binary | /Library/Caches/com.apple.act.mond | | Windows | PowerShell | %PROGRAMDATA%\wt.exe | | Linux | Python | /tmp/ld.py |

The dropper then deleted itself and replaced its own package.json with a clean copy — erasing forensic evidence of the postinstall trigger from node_modules. The entire process, from install to full compromise, took approximately 15 seconds.

The RAT shared an identical C2 protocol, command set, and beacon cadence across all three platforms. This is a single cross-platform implant framework with platform-native implementations — not three independent tools.

Attribution

Google's Threat Intelligence Group (GTIG) publicly attributed this attack to UNC1069, a North Korea-nexus APT, on April 1, 2026. The absence of ransomware or cryptocurrency mining components signals espionage and credential harvesting as the primary objective, not financial crime.

Mandiant CTO Charles Carmakal noted that stolen secrets from this attack "will enable more software supply chain attacks, SaaS environment compromises, and crypto heists over the next several months."

How to check your system

Run the following from inside any Node.js project.

All platforms — project scope:

npm list axios
npm list plain-crypto-js
grep -E "plain-crypto-js|1\.14\.1|0\.30\.4" package-lock.json

macOS — system and user scope:

npm list -g axios
npm list -g plain-crypto-js
ls ~/Library/LaunchAgents/
lsof -i :8000

Windows (PowerShell) — project scope:

Select-String -Path .\package-lock.json -Pattern "plain-crypto-js"
Test-Path .\node_modules\plain-crypto-js
netstat -ano | findstr "8000"
Get-ScheduledTask | Where-Object { $_.TaskPath -notlike "\Microsoft\*" }

Linux — system and user scope:

npm list -g plain-crypto-js
ss -tnp | grep 8000
crontab -l
grep -E "curl|wget|python|nc" ~/.bashrc ~/.zshrc ~/.profile 2>/dev/null

If plain-crypto-js appears anywhere — assume full compromise.

Remediation

If you were not running axios 1.14.1 or 0.30.4, and neither package appears in your lockfile or node_modules, you are clean. Pin your version and move on.

If you were exposed:

1. Isolate immediately. Remove the machine from the network. The RAT is actively beaconing to the C2 server.

2. Do not clean in place. The dropper self-deleted. Persistence mechanisms may remain. Rebuild from a known-good state.

3. Rotate every credential that was accessible on that machine at install time: npm tokens, AWS/GCP/Azure keys, SSH private keys, CI/CD secrets, anything in .env files.

4. Audit your CI/CD pipeline for runs during the 00:21–03:29 UTC window on March 31. Any ephemeral runner that pulled a fresh install during that window should have its injected secrets rotated immediately.

5. Downgrade and pin:

# 1.x branch
npm install axios@1.14.0

# 0.x legacy branch
npm install axios@0.30.3

Remove the ^ caret from your package.json and use npm ci in CI/CD pipelines instead of npm install.

6. Block the C2 domain at your DNS level or firewall:

sfrclak.com
142.11.206.73:8000

Safe versions

| Version | Status | |---|---| | axios 1.14.0 | Safe — last legitimate 1.x release with SLSA provenance | | axios 0.30.3 | Safe — last known-clean legacy release | | axios 1.14.1 | Malicious | | axios 0.30.4 | Malicious | | plain-crypto-js 4.2.1 | Malicious — presence = compromise | | plain-crypto-js 4.2.0 | Decoy — clean but should not be in your projects |

Going forward

This attack succeeded because of a long-lived npm access token with no expiry — a single credential that bypassed OIDC protections entirely.

The controls that would have caught it:

  • Lockfile enforcement in CI: npm ci instead of npm install
  • Exact version pins: "axios": "1.14.0" not "^1.14.0"
  • SLSA/OIDC provenance checks: absence of provenance on a major package release is an immediate red flag
  • Postinstall script auditing: most production builds do not need lifecycle scripts
  • Short-lived tokens: no npm publish token should be long-lived or unscoped

Sources: Elastic Security Labs, StepSecurity, Snyk, Google GTIG via Help Net Security, Wiz Research, Trend Micro — March/April 2026.

[ END_OF_LOG ]

< BACK_TO_FIELD_NOTES ←

[ GET_FIELD_NOTES_EARLY ]

Next field note goes to subscribers first. No cadence. Only when something matters.