# Axios npm Supply Chain Compromise — Malicious axios@1.14.1 and axios@0.30.4 Inject plain-crypto-js@4.2.1 RAT Dropper

> On 2026-03-31, two malicious releases of the Axios HTTP client (axios@1.14.1 and axios@0.30.4) were published to the npm registry from a compromised maintainer account, adding a phantom runtime dependency plain-crypto-js@4.2.1 whose postinstall hook drops a cross-platform remote access trojan that beacons to sfrclak[.]com:8000. CISA issued a formal alert on 2026-04-20 directing organizations to audit every Node.js build, CI/CD pipeline, and developer workstation that ran npm install or npm update during the approximately 3-hour exposure window, downgrade to axios@1.14.0 or axios@0.30.3, rotate all exposed credentials, and hunt for persistent artifacts such as /Library/Caches/com.apple.act.mond (macOS) and %PROGRAMDATA%\wt.exe (Windows).

- **Published:** 2026-04-20T12:00:00Z
- **Last reviewed:** 2026-10-19T15:13:04.866Z
- **Canonical:** https://intel.threadlinqs.com/threat/TL-2026-0397
- **ID:** TL-2026-0397
- **Severity:** CRITICAL (CVSS 9.8)
- **Category:** SUPPLY_CHAIN
- **Status:** MONITORING
- **Actor:** UNC1069 (North Korea)
- **Detections:** 9 · **IOCs:** 38 (full data via the Threadlinqs MCP server — Purple tier)

## Description

On 2026-03-31 at 00:21 UTC the attacker, operating through a hijacked npm account belonging to long-time Axios maintainer jasonsaayman, published axios@1.14.1 to the npm registry. Thirty-nine minutes later at 01:00 UTC the same account published axios@0.30.4 into the legacy 0.x branch. Both releases carry bit-for-bit identical library source, dist bundles, type definitions, README, and CHANGELOG compared to their prior clean versions (1.14.0 and 0.30.3, respectively) — the only substantive diff is a single line added to package.json: the declaration of a new runtime dependency on plain-crypto-js@^4.2.1. The attacker also removed the prepare: husky script, a tell-tale artifact of a manual npm publish that bypassed the Axios project''s GitHub Actions OIDC Trusted Publisher pipeline. Registry metadata confirms the tampering: every legitimate axios@1.x release carries a _npmUser.trustedPublisher GitHub OIDC binding, while axios@1.14.1 was published with a stolen long-lived classic npm access token tied to the attacker-controlled ProtonMail address ifstap@proton.me, with no corresponding commit or tag in the axios GitHub repository.

The plain-crypto-js package was pre-staged to defeat zero-history heuristics. At 2026-03-30 05:57 UTC, attacker account nrwise@proton.me published a benign plain-crypto-js@4.2.0 containing a bit-for-bit copy of the legitimate crypto-js@4.2.0 library (Evan Vosberg, brix/crypto-js) with no postinstall hook. Eighteen hours later, at 23:59 UTC the same day, plain-crypto-js@4.2.1 was published — a file-level diff against 4.2.0 shows exactly three changes: package.json gains a postinstall: "node setup.js" hook, a new 4.2 KB obfuscated dropper file setup.js is added, and a file named package.md containing a clean package.json stub is added for post-execution replacement. All 56 crypto source files remain byte-identical to the decoy, so diff-based analysis against crypto-js finds nothing anomalous in library code. plain-crypto-js is never require()''d anywhere in the axios source — it is a phantom dependency whose sole reason to exist is to fire its postinstall hook.

setup.js is a single minified file using a two-layer obfuscation scheme: sensitive strings (Node module names, OS identifiers, shell commands, the C2 URL, file paths) are stored in an encoded array stq[]; an outer base64/reverse/underscore-to-equals transform feeds into an inner XOR decoder keyed with the string "OrDeR_7077" (whose non-numeric characters resolve to 0 under Number(), producing an effective key of [0,0,0,0,0,0,7,0,7,7]). The dropper''s entry call _entry("6202033") concatenates the decoded base http://sfrclak.com:8000/ with campaign ID 6202033 to produce the C2 URL http://sfrclak.com:8000/6202033. Three platform branches execute:

- macOS (darwin): writes an AppleScript to /tmp/6202033, invokes it via nohup osascript; the AppleScript POSTs packages.npm.org/product0 to the C2, downloads the macOS stage-2 binary to /Library/Caches/com.apple.act.mond (reverse-DNS-styled name abbreviating "Activity Monitor Daemon" to blend with legitimate Apple caches), chmod 770''s it, spawns it via /bin/zsh, and deletes the AppleScript.
- Windows (win32): locates PowerShell via where powershell and copies it to %PROGRAMDATA%\wt.exe (a name that squats on Windows Terminal), creating persistence that survives reinstalls. A VBScript dropped at %TEMP%\6202033.vbs is invoked via cscript //nologo; it curl POSTs packages.npm.org/product1 to the C2, saves the returned PowerShell stage-2 to %TEMP%\6202033.ps1, launches it with -WindowStyle Hidden -ExecutionPolicy Bypass, and self-deletes.
- Linux / other: curl -o /tmp/ld.py POSTs packages.npm.org/product2 to the C2, chains with && nohup python3 /tmp/ld.py in the background, detached from the npm process tree. The trailing & reparents the python3 process to PID 1 (init) as soon as execSync returns.

Every payload runs in the background; execSync returns in under a second so npm install completes normally with exit code 0. The dropper then performs anti-forensic self-cleanup: fs.unlink(__filename) deletes setup.js, fs.unlink("package.json") removes the malicious manifest, and fs.rename("package.md", "package.json") installs the clean 4.2.0 stub. Post-infection, npm list plain-crypto-js reports 4.2.0 — not 4.2.1 — because the stub manifest reports the older version number, a deliberate mismatch designed to mislead incident responders who were told to look for 4.2.1. npm audit returns nothing. Only the existence of the node_modules/plain-crypto-js/ directory itself and persistent artifacts (wt.exe, com.apple.act.mond, /tmp/ld.py) remain as evidence. An outer try/catch swallows every error silently: unreachable C2, permission denied, anything — npm install always exits 0.

The releases were live for roughly 2h53m (1.14.1) and 2h15m (0.30.4) before npm''s security response. At approximately 03:15 UTC npm unpublished both axios versions and reverted the latest dist-tag to 1.14.0. At 03:25 UTC npm placed plain-crypto-js on security hold; at 04:26 UTC the registry published the replacement stub plain-crypto-js@0.0.1-security.0 under npm@npmjs.com. Any project that executed npm install or npm update against the resolved registry during the window — or whose CI job or Docker build cached either version — is assumed compromised. StepSecurity Harden-Runner confirmed live callbacks to sfrclak.com:8000 from CI runs (including the backstage/backstage GitHub Actions workflow) during the exposure window. CISA published its formal advisory on 2026-04-20, 20 days after the npm registry response, driving broad enterprise disclosure.

## MITRE ATT&CK

- T1583 Acquire Infrastructure
- T1583.001 Acquire Infrastructure: Domains
- T1583.004 Acquire Infrastructure: Server
- T1586 Compromise Accounts
- T1587.001 Develop Capabilities: Malware
- T1608.001 Stage Capabilities: Upload Malware
- T1195.001 Supply Chain Compromise: Compromise Software Dependencies and Development Tools
- T1195.002 Supply Chain Compromise: Compromise Software Supply Chain
- T1078.004 Valid Accounts: Cloud Accounts
- T1059.001 Command and Scripting Interpreter: PowerShell
- T1059.003 Command and Scripting Interpreter: Windows Command Shell
- T1059.004 Command and Scripting Interpreter: Unix Shell
- T1059.005 Command and Scripting Interpreter: Visual Basic
- T1059.006 Command and Scripting Interpreter: Python
- T1059.007 Command and Scripting Interpreter: JavaScript
- T1059.002 Command and Scripting Interpreter: AppleScript
- T1204.002 User Execution: Malicious File
- T1574.005 Hijack Execution Flow: Executable Installer File Permissions Weakness
- T1036.005 Match Legitimate Resource Name or Location
- T1036.004 Masquerading: Masquerade Task or Service
- T1036.003 Rename Legitimate Utilities
- T1027 Obfuscated Files or Information
- T1027.013 Obfuscated Files or Information: Encrypted/Encoded File
- T1140 Deobfuscate/Decode Files or Information
- T1070.004 Indicator Removal: File Deletion
- T1564.003 Hide Artifacts: Hidden Window
- T1218 System Binary Proxy Execution
- T1552.001 Unsecured Credentials: Credentials In Files
- T1552.007 Container API
- T1528 Steal Application Access Token
- T1082 System Information Discovery
- T1033 System Owner/User Discovery
- T1071.001 Application Layer Protocol: Web Protocols
- T1105 Ingress Tool Transfer
- T1571 Non-Standard Port
- T1102.002 Web Service: Bidirectional Communication
- T1041 Exfiltration Over C2 Channel
- T1565.001 Data Manipulation: Stored Data Manipulation
- T1547.001 Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder

## Sources

- [CISA Alert — Supply Chain Compromise Impacts Axios Node Package Manager](https://www.cisa.gov/news-events/alerts/2026/04/20/supply-chain-compromise-impacts-axios-node-package-manager)
- [Post Mortem: axios npm supply chain compromise (Issue #10636)](https://github.com/axios/axios/issues/10636)
- [Microsoft Security Blog — Mitigating the Axios npm supply chain compromise](https://www.microsoft.com/en-us/security/blog/2026/04/01/mitigating-the-axios-npm-supply-chain-compromise/)
- [StepSecurity — axios Compromised on npm: Malicious Versions Drop Remote Access Trojan](https://www.stepsecurity.io/blog/axios-compromised-on-npm-malicious-versions-drop-remote-access-trojan)
- [Socket — Supply Chain Attack on Axios Pulls Malicious Dependency from npm](https://socket.dev/blog/supply-chain-attack-on-axios)
- [npm Docs — Securing your code](https://docs.npmjs.com/packages-and-modules/securing-your-code)
- [Axios npm package](https://www.npmjs.com/package/axios)
- [Axios GitHub repository](https://github.com/axios/axios)

## Full data

Detection queries (Splunk SPL / Microsoft KQL / Sigma) and IOC values require the Threadlinqs MCP server (Purple tier): https://intel.threadlinqs.com/mcp

Canonical: https://intel.threadlinqs.com/threat/TL-2026-0397
