Skip content

Axios Supply Chain Attack: What happened and how to protect your environment

On 31 March 2026, attackers used the compromised npm account of the lead maintainer of Axios to publish two malicious versions of the package to the registry. The compromised releases carried a new dependency that includes a cross-platform dropper which retrieves and deploys a platform-specific remote access trojan (RAT) onto any machine that installed the package via npm. The dropper contacts a hardcoded command-and-control server, downloads platform-specific payloads for macOS, Windows, or Linux, then erases all evidence of itself and the malicious content in the package from disk, leaving only the deployed RAT.

What is Axios?

Axios is the JavaScript ecosystem's most widely used HTTP client library. Frontend frameworks, backend services, CI/CD tooling, enterprise internal apps - if it makes an HTTP request in Node.js or the browser, there's a good chance Axios is involved. Any project using a standard caret range like ^1.14.0 in its package.json would have silently resolved to the malicious version on its next install, with no visible change to the Axios source code and no indication from the package name, publisher, or version number that anything was wrong.

Axios has over 100 million weekly downloads and sits in the dependency tree of almost all Node.js applications that make HTTP requests, giving this the potential to be an extremely impactful compromise.

How was this discovered?

Socket Security's automated scanner flagged the malicious dependency plain-crypto-js@4.2.1 within six minutes of publication. StepSecurity independently identified both compromised Axios versions and published a full technical teardown, confirming through runtime analysis that the malware made its first C2 callback 1.1 seconds after npm install started.

Feross Aboukhadijeh, Socket's co-founder, posted the public alert:

"Active supply chain attack on axios – one of npm's most depended-on packages. This is textbook supply chain installer malware."

The npm security team pulled both poisoned versions and replaced them with security-holder stubs. axios@1.14.1 had been live for roughly three hours, axios@0.30.4 for about two hours and fifteen minutes. During that window, the legitimate maintainer Jason Saayman was locked out of his own account, and an Axios collaborator reported on GitHub that they could not revoke the attacker's access because the attacker's permissions exceeded their own.

Technical breakdown

Affected versions

The two compromised releases are axios@1.14.1 and axios@0.30.4. Both the modern 1.x and legacy 0.x branches were poisoned within 39 minutes of each other. Safe versions to pin are axios@1.14.0 and axios@0.30.3. Socket also identified two additional packages distributing the same payload through vendored dependencies: @shadanai/openclaw and @qqbrowser/openclaw-qbot@0.0.130.

How the attack unfolded

The attacker compromised the jasonsaayman npm account (Axios's lead maintainer), changed its registered email to an anonymous ProtonMail address, and published both malicious versions directly via the npm CLI, completely bypassing the project's normal GitHub Actions pipeline. No corresponding commits, tags, or releases exist in the Axios GitHub repository for either version.

Eighteen hours before the Axios compromise, a throwaway account (nrwise, also using ProtonMail) published plain-crypto-js@4.2.0. This is a clean copy of the legitimate crypto-js library, designed solely to build npm publishing history and avoid zero-history scanner flags.

At 23:59 UTC on 30 March, the attacker published plain-crypto-js@4.2.1 with an obfuscated dropper payload and a pre-staged clean package.json stub ready for post-execution evidence destruction.

Twenty-two minutes later, axios@1.14.1 went live with a single new dependency added: "plain-crypto-js": "^4.2.1", a package never imported or referenced anywhere in the Axios codebase. Its only purpose was to trigger npm's postinstall hook.

Exploit flow

The dropper (setup.js) uses two-layers obfuscation, string reversal plus base64, then XOR decryption to hide all sensitive strings at rest and decode them only at runtime. It dynamically imports child_process, os, and fs to avoid detection through static analysis, then branches based on the target operating system:

  1. npm resolves plain-crypto-js@4.2.1 as a dependency of the compromised Axios version and installs it automatically.
  2. The postinstall hook fires, executing node setup.js before npm install finishes.
  3. The dropper identifies the OS via os.platform() and contacts the C2 server at sfrclak[.]com:8000 with a platform identifier, disguised as an npm registry URL in the POST body.
  4. Platform-specific RAT delivery:
    • macOS: AppleScript downloads a binary to /Library/Caches/com.apple.act.mond (mimicking an Apple daemon name), sets it executable, and launches it via /bin/zsh.
    • Windows: Copies legitimate powershell.exe to %PROGRAMDATA%\wt.exe (disguised as Windows Terminal), then executes a hidden VBScript/PowerShell chain to fetch and run the RAT with -ExecutionPolicy Bypass.
    • Linux: curl fetches a Python RAT to /tmp/ld.py and runs it detached with nohup python3, ensuring it survives after the parent process exits.
  5. Self-destruction: The dropper deletes setup.js, removes the package.json containing the postinstall hook, and renames a pre-staged clean stub into its place. Post-infection inspection of node_modules/plain-crypto-js/ reveals nothing suspicious.

StepSecurity's full static and runtime analysis, including decoded dropper strings and the Harden-Runner process tree, is available at https://www.stepsecurity.io/blog/axios-compromised-on-npm-malicious-versions-drop-remote-access-trojan.

Socket's analysis can be found at https://socket.dev/blog/axios-npm-package-compromised.

An important characteristic of the RAT is that it has no persistence mechanism. If an infected device is rebooted then while the binary will still exist on the disk, it will not be executed. This could be intentional by the attacker, as setting up a persistence mechanism would make the RAT more visible to EDR and defenders. Alternatively, it could be that the RAT was intended to connect to the C2 server and either retrieve a secondary payload, or receive commands which would set up persistence. It could be that the attacker intended to reserve persistence functionality only for their intended targets or high value victims.

Attribution and purpose

At present it is not possible to attribute this attack to a particular actor, or to identify the goals or motivations of the attacker, although the attack appears to have been capable and to have prioritised stealth in its payloads and functionality.

The RAT functionality is generic and versatile, as expected of an initial stage RAT, with hardcoded commands of:

  1. Self-removal
  2. Download and execution of a binary
  3. Script and command execution
  4. Enumeration of directories (hard coded targets were /home/user/.ssh and /etc/passwd)

The RAT functionality could be of use to any attacker, and by not including specific malicious functionality (such as crypto mining or credential theft) it is less likely that the RAT would be picked up by EDR. The compromise of the packages was rapid and the actions taken relatively stealthy, however this does not narrow down the actor to either a nation state or financially motivated attacker, any number of which could be capable of this attack if they had access to the maintainer’s account

DPRK actors have repeatedly performed software supply chain attacks targeting crypto developers. While Axios is not exclusively used for cryptocurrency related software projects, it is extremely widely used, and so would likely overlap with that subset of developers. There is no other reason to associate it with DPRK at present, however.

The XOR key used includes multiple 7s, often an indication that the actor is Chinese, but it also seemingly references Star Wars “Order 66”, which is not a popular franchise in China.

It may be possible to attribute the attack through forensic analysis of the C2, of the compromised maintainer account actions by npm and/or GitHub, or of the method of compromise of the maintainer’s account, though attribution of the attack may not bring much additional clarity.

How to detect whether you are affected

  1. Check your lockfile for references to axios@1.14.1, axios@0.30.4, or plain-crypto-js. If node_modules/plain-crypto-js/ exists in any project, the dropper ran on that machine, even though the cleanup routine will have replaced its contents with an innocent-looking stub.
  2. Check for RAT artifacts at the platform-specific paths: /Library/Caches/com.apple.act.mond on macOS, %PROGRAMDATA%\wt.exe on Windows, and /tmp/ld.py on Linux. Note that the dropper's self-cleanup means these may already be gone.
  3. Check network telemetry for any outbound connections to sfrclak[.]com or 11.206.73 on port 8000. This is your most reliable indicator, since filesystem artifacts self-delete but network logs persist.
  4. Audit CI/CD pipelines for any workflow that ran npm install between roughly 00:21 and 03:15 UTC on March 31. These had access to injected secrets and deployment keys.

If you suspect you are affected

Downgrade to axios@1.14.0 or axios@0.30.3, remove node_modules/plain-crypto-js, and reinstall with npm install --ignore-scripts. If you find RAT artifacts, treat the system as fully compromised and rebuild from a known-good image.

Rotate all credentials that were accessible on the compromised machine: saved passwords, npm or other tokens, SSH keys, cloud access keys, .env contents, and CI/CD secrets.

Block sfrclak[.]com and 142.11.206.73 at your firewall and DNS layer.

Hardening your supply chain

  1. Pin exact dependency versions and commit your lockfile. Caret ranges are what allowed automatic resolution to the malicious release. Use npm ci in CI/CD to enforce lockfile-only installs.
  2. Disable postinstall scripts in automated builds with npm ci --ignore-scripts. The entire attack chain depends on npm's postinstall lifecycle hook, and most packages don't need it.
  3. Enforce a minimum package age, e.g. by setting min-release-age=7 in .npmrc. Tools like Aikido's Safe Chain can also block packages published within a configurable cooldown window. The malicious plain-crypto-js@4.2.1 package version had existed for less than 24 hours, and even a 48-hour age gate for new packages would have prevented exploitation.
  4. Control egress traffic from CI/CD runners – the dropper phones home within 1.1 seconds of install. If your runners allow unrestricted outbound connections, any postinstall script can reach any C2 server.

A familiar story

The Axios compromise follows the same pattern as every major npm supply chain attack in the past year: compromised maintainer credentials, a small change to the dependency manifest, a postinstall hook running a self-deleting payload. In September 2025, phished credentials led to the compromise of Chalk and Debug (over 2 billion combined weekly downloads). That same month, the Shai-Hulud worm became the first wormable npm malware in history. By December, its second iteration had harvested roughly 400,000 developer secrets.

Recently, npm has announced planned security improvements such as mandatory FIDO 2FA, disabling automation tokens by default, and enforced trusted publishing. At present however these improvements remain in development. Until they are implemented it is third-party tools and developer awareness that must catch what npm does not.

Need help?

If you suspect your organisation has been affected by this incident and you need urgent assistance, or you want to assess your supply chain exposure before the next attack, LRQA can help.

Get in touch 

 

Indicators of Compromise (IOCs)

Network

 

C2 domain - hxxp

//sfrclak[.]com:8000

C2 IP

 142.11.206.73:8000

C2 URL

 hxxp:////sfrclak[.]com:8000/6202033

User-Agent string

 mozilla/4.0 (compatible; msie 8.0; windows nt 5.1; trident/4.0)

Mac C2 payload retrieval POST body

 packages.npm.org/product0

Windows C2 payload retrieval POST body

 packages.npm.org/product1

Linux C2 payload retrieval POST body

 packages.npm.org/product2

   

Mac Host

 

MacOS temporary file (deleted after use)

 /tmp/6202033

MacOS RAT binary file

 /Library/Caches/com.apple.act.mond

Injected binaries from RAT activity

 /private/tmp/.[XXXXXX]

Mac RAT SHA256

 92ff08773995ebc8d55ec4b8e1a225d0d1e51efa4ef88b8849d0071230c9645a

Mac RAT SHA1

 13ab317c5dcab9af2d1bdb22118b9f09f8a4038e

Mac RAT MD5

 7a9ddef00f69477b96252ca234fcbeeb

   

Windows Host

 

Copies powershell.exe to

 %PROGRAMDATA%\wt.exe

VBS wrapper, deleted after use

 %TEMP%\6202033.vbs

Powershell payload, deleted after use

 %TEMP%\6202033.ps1

   

Linux Host

 

Linux temporary file

 /tmp/ld.py

   

NPM Packages

 

axios@1.14.1 shasum

 2553649f232204966871cea80a5d0d6adc700ca

axios@0.30.4 shasum

 d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71

plain-crypto-js@4.2.1 shasum

 07d889e2dadce6f3910dcbc253317d28ca61c766

Post compromise activity

After payload execution, the dropper removes any indication of the malicious code from the package directory by deleting setup.js and package.json, replacing package.json with a legitimate/clean file.

   

Notable strings

 

XOR key - OrDeR_7077

 

XOR constant - 333

 

Campaign id

6202033

Plain-crypto-js@4.2.0 publisher

 nrwise@proton.me

Attacker controlled email address used in axios maintainer account hijack

 ifstap@proton.me

Attacker controlled email address used to publish plain-crypto-js

 nrwise@proton.me

   

Npm audit commands

 

Check for existence of plain-crypto-js

npm ls plain-crypto-js

Check for existence of plain-crypto-js

cat package-lock.json | grep -A3 "plain-crypto-js"

Check for existence of malicious axios versions

grep -E '"axios".*"(1\.14\.1|0\.30\.4)"' package-lock.json

 

Latest news, insights and upcoming events