# axios Compromised on npm - Malicious Versions Drop Remote Access Trojan

Hijacked axios maintainer account published poisoned npm releases injecting plain-crypto-js, whose postinstall dropped a cross-platform RAT then self-destructed.

- Payout: Real-world hack
- Severity: critical
- Program: axios
- Analysis by: StepSecurity
- Disclosed: 2026-04-09
- Write-up quality: 9/10
- Original: https://www.stepsecurity.io/blog/axios-compromised-on-npm-malicious-versions-drop-remote-access-trojan
- Library page: https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-axios-compromised-on-npm-malicious-versions-drop-remote-access-trojan
- Tags: area:oss domain:oss impact:internal-access impact:rce kind:incident platform:threat-intel sev:critical tech:ci-cd tech:nodejs technique:recon technique:source-review vuln:misconfiguration vuln:rce vuln:secrets-leak

**Target:** npm package axios (1.14.1, 0.30.4) and dependency plain-crypto-js@4.2.1
**Root cause:** Attacker used a stolen long-lived npm token for maintainer jasonsaayman (bypassing OIDC Trusted Publisher) to add a never-imported dependency plain-crypto-js@4.2.1 whose postinstall runs an obfuscated RAT dropper.
**Steps:**
1. Compromise jasonsaayman npm account, change email to ifstap@proton.me
2. Publish clean decoy plain-crypto-js@4.2.0 (copy of crypto-js) 18h earlier to build history
3. Publish plain-crypto-js@4.2.1 adding `"postinstall": "node setup.js"` and obfuscated setup.js
4. Publish axios@1.14.1 and axios@0.30.4 with `plain-crypto-js: ^4.2.1` added to dependencies, no gitHead/OIDC
5. Victim runs `npm install axios@1.14.1`; npm executes postinstall `node setup.js`
6. setup.js decodes stq[] strings (XOR key OrDeR_7077 + base64/reverse) and calls `_entry("6202033")`
7. Platform branch fetches stage-2 from `http://sfrclak.com:8000/6202033` with POST body packages.npm.org/product0/1/2
8. Dropper deletes setup.js, deletes package.json, renames package.md (v4.2.0 stub) to package.json
**How found:** StepSecurity AI Package Analyst flagged the anomalous dependency; Harden-Runner detected never-before-seen outbound connection to sfrclak.com:8000 during a CI run in the backstage repo, prompting static deobfuscation of setup.js and runtime validation.
**Exploitation:** On install, postinstall detaches a platform payload: macOS AppleScript downloads RAT to /Library/Caches/com.apple.act.mond and runs via zsh; Windows copies powershell to %PROGRAMDATA%\wt.exe and runs a VBScript fetching a .ps1 with -ep bypass; Linux curls /tmp/ld.py and runs it via nohup python3. All errors swallowed so npm install exits 0.
**Escalation:** Poisoned both 1.x and 0.x branches within 39 minutes to maximize installs; pre-staged decoy and clean stub to evade scanners and forensics; orphaned process to PID 1 to defeat attribution.
**Insight:** A dependency present in package.json but never require()'d anywhere in the source is a high-confidence compromise signal; also compare _npmUser/trustedPublisher/gitHead in registry metadata — a publish lacking OIDC binding and gitHead indicates a stolen long-lived token.
