Cross-Platform Threat - Axios Package Compromise

Shavit Satou, JFrog Security Researcher | 31 Mar, 2026

The JFrog security research team recently identified a supply chain attack targeting the axios npm package. If you installed axios@1.14.1, or axios@0.30.4 you must assume your environment is compromised. Note that more packages have been compromised in this ongoing attack, see section “Known Malicious Packages” below.

This isn't a runtime backdoor. The attackers didn't touch the HTTP client logic in Axios. Instead, they added a new dependency, plain-crypto-js version 4.2.1, to axios-1.14.1’s package.json manifest. They did this to get code execution when you run npm install.
We know this was deliberate because Axios doesn't even import plain-crypto-js anywhere in its code. The package only exists to trigger the installation hook.

In addition to the plain-crypto-js package, 3 more packages contain the same payload: @shadanai/openclaw and @qqbrowser/openclaw-qbot. Even though they were not injected into Axios, users who installed them should also take counter-measures.

The malicious dependency relies on an obfuscated postinstall script (setup.js). It hides its strings using a two-step transform: reversing the text, base64-decoding it, and XORing the result against a hardcoded key (OrDeR_7077) as well as the constant 333.

Once deobfuscated, the script does a few things. It figures out your operating system, creates a temporary file, and reaches out to hxxp[:]//sfrclak[.]com:8000/. It uses a POST request, and the body of the request tells the server which OS-specific payload to return (/product0 for macOS, /product1 for Windows, /product2 for Linux).

The server acts as a switchboard, handing out different backdoors depending on the victim's machine:

Windows: The script finds your PowerShell binary and copies it to %PROGRAMDATA%\wt.exe. It then drops VBScript and PowerShell launchers to fetch the second stage. The final payload is a full PowerShell backdoor. It gains persistence by dropping %PROGRAMDATA%\system.bat and adding a registry Run key. Every time you log in, it re-downloads the backdoor straight into memory.

macOS: The script writes an AppleScript file to a temporary directory (/tmp/.XXXXXX.scpt) and launches it with osascript. This fetches a compiled Mach-O binary and saves it to a hidden drop path like /private/tmp/.%s or directly to /Library/Caches/com.apple.act.mond. It marks the file as executable and runs it in the background using zsh. Reverse-engineering this universal FAT Mach-O (x86_64 and arm64) reveals it's written in C++ using nlohmann::json, relies on libcurl for networking, and expects the C2 URL via argv[1]. The binary also leaks developer environment paths as a bonus opsec failure (/Users/mac/Desktop/Jain_DEV/client_mac/macWebT/macWebT/...), and contains debug-style entitlements (com.apple.security.get-task-allow = true) instead of a hardened production signature.

Linux: The fallback path is simpler. It downloads a Python script to /tmp/ld.py and runs it in the background. We didn't find any persistence mechanisms in the Linux sample we recovered.

All three payloads share the same operator model. They profile your host using platform-specific mechanisms (e.g., querying WMI classes like Win32_OperatingSystem on Windows, walking /proc/<pid>/cmdline and /proc/<pid>/stat on Linux, or using sysctl on macOS). They steal the current username, grab process lists, and scan your directories. They wrap this data in JSON, Base64-encode it, and POST it back to the command and control server. Curiously, they all use a fake, hardcoded Internet Explorer 8 User-Agent string to blend in.

Once running, the backdoors continuously beacon the server waiting for tasks. They distinguish between an initial FirstInfo beacon (a deep system and filesystem inventory) and recurring BaseInfo beacons. They support commands to run arbitrary scripts, enumerate directories, and inject payloads directly into memory.

Despite the sophisticated cross-platform design, the threat actors made several errors:

  • Windows: The script contains noisy debugging code (Write-Host $data prints raw server tasking JSON to the console), unused variables, and an inconsistent success reporting mechanism for its in-memory injection (peinject), returning the string "Wow" instead of the expected structured object.
  • Linux: The intended generic temp-drop executor for payload injection is broken due to an undefined variable and incorrect byte decoding. Furthermore, process enumeration truncates commands under 60 characters, UID parsing is fragile, and the payload drops temporary files using world-writable rwxrwxrwx permissions. This means that the threat actor did not have full execution capacity on Linux targets! However, the rest of the capabilities (e.g. running arbitrary scripts) is still functional.

The cleanup routine is what stands out the most - they downgrade plain-crypto-js to a version that didn’t contain the malicious payload, 4.2.0.

After the initial payload fires, setup.js executes the following:

  1. It deletes itself.
  2. It deletes the active, malicious package.json.
  3. It renames a clean backup file (package.md) to package.json.

The restored manifest has no postinstall script. If you check your node_modules folder later, it looks like a normal, older release. The attackers intentionally destroy their own first-stage evidence to evade forensic review.

If you installed axios@1.14.1 or axios@0.30.4, your machine or CI/CD runner is likely compromised. Take these steps immediately.

The malware scans the system and can execute arbitrary scripts from the C2 server. Any secrets on the machine are at risk.

  • Rotate all secrets that were accessible in the environment. This includes AWS keys, npm tokens, SSH keys, and database passwords.
  • Check your registry or source control logs for any unauthorized access or pushes.

If you are on Windows, you must remove the persistence mechanism:

  • Delete the registry key: HKCU\Software\Microsoft\Windows\CurrentVersion\Run\MicrosoftUpdate
  • Delete the dropped batch file: %PROGRAMDATA%\system.bat
  • Delete the copied PowerShell binary: %PROGRAMDATA%\wt.exe

On macOS and Linux, the attacker executes scripts from temporary directories. Rebooting the machine and clearing the /tmp folder will stop the current execution, but wiping the machine entirely is the safest approach since the attacker had remote code execution capabilities.

Get the compromised packages out of your project.

  • Delete your node_modules folder and clean the npm cache:
rm -rf node_modules
npm cache clean --force
  • Downgrade Axios to a safe version in your package.json and package-lock.json.
  • Reinstall dependencies.

  • Run npm config set ignore-scripts true to stop postinstall hooks from running automatically.
  • JFrog Curation: Implement automated dependency scanning and approval workflows with JFrog Curation to ensure only vetted packages enter your supply chain.

Package Name Malicious Versions Xray ID
axios 1.14.1, 0.30.4 XRAY-958970
plain-crypto-js 4.2.1 XRAY-958969
@shadanai/openclaw 2026.3.31-2, 2026.3.31-1, 2026.3.28-3, 2026.3.28-2 XRAY-958979
@qqbrowser/openclaw-qbot 0.0.130 XRAY-958980

In light of recent TeamPCP incidents, the frequent compromise of popular packages has become an expected reality.
The cross-platform capabilities of this specific attack are particularly concerning for users on all operating systems, despite the technical errors found in the attackers' Linux-specific payload.

Anyone who has utilized the packages mentioned in the preceding table should initiate remediation protocols immediately and operate under the assumption that their sensitive credentials and secrets are now compromised.

JFrog Xray and JFrog Curation already provide detection for these malicious packages, which can be identified using the specific Xray IDs provided in the technical summary.

  • axios-1.14.1
  • plain-crypto-js-4.2.1
  • @shadanai/openclaw
  • @qqbrowser/openclaw-qbot

  • URL: hxxp[:]//sfrclak[.]com:8000/6202033
  • Domain: sfrclak[.]com

  • com.apple.act.mond, SHA-256: 92ff08773995ebc8d55ec4b8e1a225d0d1e51efa4ef88b8849d0071230c9645a
  • 6202033.ps1, SHA-256: 617b67a8e1210e4fc87c92d1d1da45a2f311c08d26e89b12307cf583c900d101
  • ld.py, SHA-256: fcb81618bb15edfdedfb638b4c08a2af9cac9ecfa551af135a8402bf980375cf
  • system.bat, SHA-256: f7d335205b8d7b20208fb3ef93ee6dc817905dc3ae0c10a0b164f4e7d07121cd
  • setup.js, SHA-256: e10b1fa84f1d6481625f741b69892780140d4e0e7769e7491e5f4d894c2e0e09