DEV Community

Cover image for axios Got Hacked. If You Ran npm install Yesterday, Read This Now.
Alan West
Alan West

Posted on

axios Got Hacked. If You Ran npm install Yesterday, Read This Now.

axios. The HTTP client thats in basically every JavaScript project on earth. 100 million weekly downloads. Present in roughly 80% of cloud environments according to Wiz. And as of yesterday, two of its versions were shipping a remote access trojan.

This isnt a theoretical vulnerability. This is a full supply chain compromise. If you ran npm install between approximately 00:21 and 03:15 UTC on March 31, 2026, and your dependency tree pulled axios@1.14.1 or axios@0.30.4, a RAT was dropped on your machine. macOS, Windows, Linux. All three.

What Happened

StepSecurity identified the attack on March 30. The attacker compromised the npm account of jasonsaayman, the lead maintainer of the axios project. They changed the accounts email to ifstap@proton.me (an attacker-controlled ProtonMail address) and used the stolen credentials to publish two malicious versions.

The critical detail: legitimate axios releases are published through GitHub Actions using OIDC trusted publishing. These malicious versions were published manually via a stolen access token with no OIDC binding. That pattern break is what made the attack detectable.

Timeline (UTC, March 30-31):

  • 05:57 — plain-crypto-js@4.2.0 published (clean decoy, staged 18 hours early)
  • 23:59 — plain-crypto-js@4.2.1 published (malicious payload added)
  • 00:21 — axios@1.14.1 released
  • 01:00 — axios@0.30.4 released (39 minutes later, covering both major branches)
  • ~03:15 — npm unpublished both versions
  • 04:26 — npm replaced plain-crypto-js with a security stub

The malicious versions were live for roughly 2-3 hours. In that window, Snyk reported execution in 3% of affected environments.

How the Attack Works

The attacker added exactly one change to axios: a new dependency called plain-crypto-js@4.2.1 in package.json. Nothing else changed across all 86 files in the package.

plain-crypto-js is never imported anywhere in axios source code. Its sole purpose is its postinstall script, which runs a file called setup.js. That script is the RAT dropper.

The dropper uses two-layer XOR obfuscation with the key OrDeR_7077 to hide its payloads. When it runs, it contacts a C2 server at sfrclak.com (IP: 142.11.206.73, port 8000) and downloads platform-specific payloads.

macOS: Writes an AppleScript to /tmp/6202033, downloads a binary to /Library/Caches/com.apple.act.mond, executes via /bin/zsh, self-deletes.

Windows: Copies PowerShell to %PROGRAMDATA%\wt.exe (persistence), writes a VBScript to %TEMP%\6202033.vbs, downloads a payload to %TEMP%\6202033.ps1, runs with -ExecutionPolicy Bypass in a hidden window.

Linux: Downloads a Python script via curl to /tmp/ld.py, runs it detached with nohup python3 (re-parented to PID 1 so it survives the install process).

The Self-Destruct Mechanism

After deploying the payload, the dropper cleans up after itself in three steps:

  1. Deletes setup.js
  2. Deletes the malicious package.json
  3. Renames package.md (a pre-staged clean stub reporting version 4.2.0) to package.json

After this, running npm list shows plain-crypto-js@4.2.0 — the clean version. The malicious 4.2.1 evidence is gone. This anti-forensics technique means you cant just check your node_modules after the fact. The compromised package actively hides that it was ever version 4.2.1.

StepSecuritys Harden-Runner telemetry shows the first C2 contact happened 1.1 seconds after npm install completed. The attacker wasnt waiting around.

Are You Affected?

Check immediately:

# Check if you have the compromised versions
npm ls axios | grep -E "1\.14\.1|0\.30\.4"

# Check for the malicious dependency
ls node_modules/plain-crypto-js 2>/dev/null && echo "COMPROMISED" || echo "clean"

# Check for RAT artifacts
# macOS
ls -la /Library/Caches/com.apple.act.mond 2>/dev/null

# Linux
ls -la /tmp/ld.py 2>/dev/null

# Windows (PowerShell)
# Test-Path "$env:PROGRAMDATA\wt.exe"
Enter fullscreen mode Exit fullscreen mode

What to Do Right Now

If you find any evidence of compromise:

1. Treat the machine as fully compromised. The RAT had access to everything the npm process could reach. Thats your SSH keys, your AWS credentials, your .env files, your git config with tokens.

2. Rotate everything. npm tokens, cloud provider keys (AWS, GCP, Azure), SSH keys, CI/CD secrets, database credentials, API keys. All of them. Not tomorrow. Now.

3. Downgrade axios. Safe versions are 1.14.0 for the 1.x branch and 0.30.3 for the 0.x branch.

npm install axios@1.14.0
Enter fullscreen mode Exit fullscreen mode

4. Block the C2. Add to your firewall, DNS blocklist, or /etc/hosts:

0.0.0.0 sfrclak.com
# IP: 142.11.206.73
Enter fullscreen mode Exit fullscreen mode

5. Pin your dependencies. If youre using ^1.14.0 in your package.json, a fresh npm install would have pulled 1.14.1 automatically. Use exact versions or lockfiles.

6. Use --ignore-scripts in CI/CD. The attack relied entirely on the postinstall hook. Running npm ci --ignore-scripts would have prevented the payload from executing.

The Bigger Problem

This attack follows the exact same playbook as the event-stream compromise in 2018, the ua-parser-js attack in 2021, and the colors/faker incident in 2022. Maintainer account gets compromised, malicious version gets published, millions of installs happen before anyone notices.

The npm ecosystem still has no effective defense against this. Lock files help if you already have a clean install. OIDC publishing helps if the maintainer was using it (axios was, which is how the anomaly was detected). But for the 2-3 hour window between publish and removal, anyone running npm install in a fresh environment was vulnerable.

100 million weekly downloads. 80% of cloud environments. 2-3 hours of exposure. The math on that is terrifying.

Indicators of Compromise

For your security team:

Network IOCs:

  • Domain: sfrclak.com
  • IP: 142.11.206.73
  • Port: 8000
  • URL pattern: http://sfrclak.com:8000/6202033

File IOCs:

  • macOS: /Library/Caches/com.apple.act.mond
  • Windows: %PROGRAMDATA%\wt.exe
  • Linux: /tmp/ld.py
  • All: node_modules/plain-crypto-js/ directory

Package IOCs:

  • axios@1.14.1 (shasum: 2553649f232204966871cea80a5d0d6adc700ca)
  • axios@0.30.4 (shasum: d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71)
  • plain-crypto-js@4.2.1 (shasum: 07d889e2dadce6f3910dcbc253317d28ca61c766)

Attacker Accounts:

  • npm: jasonsaayman (compromised, email changed to ifstap@proton.me)
  • npm: creator of plain-crypto-js registered as nrwise@proton.me

Stay safe. Pin your deps. Rotate your keys. And maybe reconsider that postinstall script you never audited.

Top comments (0)