Date: 2026-03-31 Severity: Critical Status: Active compromise Discovered by: Elastic Security researchers
An npm maintainer account (jasonsaayman) on the widely used axios HTTP client package has been compromised. The attacker published two malicious versions of axios and a new typosquat package, plain-crypto-js, which serves as the payload delivery vehicle. At the time of discovery, both the latest and legacy dist-tags pointed to compromised versions, meaning default npm install axios resolved to a backdoored package.
The malicious dependency plain-crypto-js contains an obfuscated postinstall script that downloads and executes platform-specific stage-2 payloads from an external C2 server on macOS, Windows, and Linux. The payload self-deletes and overwrites its own package.json to evade post-incident forensic detection.
Any system that ran npm install (or equivalent) resolving axios@1.14.1 or axios@0.30.4 after 2026-03-31T00:21:58Z may have executed the stage-2 payload. This includes:
- Developer workstations
- CI/CD pipelines
- Production deployments pulling fresh installs
- Any project with
axiosas a direct or transitive dependency without a lockfile pinning to a prior safe version
| Package | Version | Status |
|---|---|---|
axios |
1.14.1 |
Malicious — tagged latest at time of discovery |
axios |
0.30.4 |
Malicious — tagged legacy at time of discovery |
plain-crypto-js |
4.2.0, 4.2.1 |
Malicious — payload delivery vehicle (postinstall backdoor) |
| Package | Version | Notes |
|---|---|---|
axios |
1.14.0 |
Last legitimate 1.x release — published via GitHub Actions OIDC with SLSA provenance |
axios |
0.30.3 |
Last legitimate 0.30.x release |
- Check your lockfiles (
package-lock.json,yarn.lock,pnpm-lock.yaml) foraxios@1.14.1,axios@0.30.4, or any version ofplain-crypto-js. If present, treat the system as potentially compromised. - Pin to safe versions: Ensure
axiosresolves to1.14.0or earlier known-good versions. - Hunt for IOCs (see Indicators of Compromise below) across developer machines and CI/CD infrastructure.
- Rotate credentials on any system where the compromised package was installed — the stage-2 payload may have exfiltrated secrets, tokens, or keys.
- Block the C2 domain
sfrclak.comat your network perimeter.
| Type | Value |
|---|---|
| C2 server | http://sfrclak.com:8000/ |
| Campaign ID | 6202033 |
| Full C2 URL | http://sfrclak.com:8000/6202033 |
| Indicator | Path |
|---|---|
| Stage-2 binary (disguised as Apple daemon) | /Library/Caches/com.apple.act.mond |
| Indicator | Path |
|---|---|
| Renamed PowerShell copy | %PROGRAMDATA%\wt.exe |
| Transient VBScript loader | %TEMP%\6202033.vbs |
| Transient PowerShell payload | %TEMP%\6202033.ps1 |
| Indicator | Path |
|---|---|
| Stage-2 Python script | /tmp/ld.py |
| Indicator | Value |
|---|---|
| Compromised account | jasonsaayman |
| Attacker email | ifstap@proton.me |
| Legitimate email (prior to compromise) | jasonsaayman@gmail.com |
The jasonsaayman maintainer email changed from jasonsaayman@gmail.com (present on all prior legitimate releases) to ifstap@proton.me on the malicious versions.
axios@1.14.0 (legitimate):
- Published via GitHub Actions OIDC trusted publisher with SLSA provenance attestations
- Dependencies:
form-data,proxy-from-env,follow-redirects
axios@1.14.1 (compromised):
- Published via direct CLI publish — no OIDC, no provenance attestations
- Only change from 1.14.0: addition of
plain-crypto-js@^4.2.1to dependencies
axios@0.30.4 (compromised):
- Published ~39 minutes after 1.14.1
- Only change from the legitimate 0.30.3: version bump and addition of
plain-crypto-js@^4.2.1to dependencies (all other files are byte-identical to 0.30.3)
- Installing
axios@1.14.1oraxios@0.30.4pullsplain-crypto-js@^4.2.1as a dependency plain-crypto-jsdeclares"postinstall": "node setup.js"in itspackage.json— this executes automatically onnpm installsetup.jsis an obfuscated multi-platform backdoor installer
The setup.js file uses a two-layer encoding scheme:
- Layer 1: String reversal + base64 decoding
- Layer 2: XOR cipher using the key
"OrDeR_7077"with a position-dependent index (7 * i² % 10)
All critical strings (module names, URLs, shell commands) are stored in an encoded array stq[] and decoded at runtime.
macOS (darwin):
- Writes an AppleScript to
$TMPDIR/<campaign_id> - The AppleScript downloads a binary from the C2 via
curlto/Library/Caches/com.apple.act.mond - Disguises the binary as an Apple system daemon
- Sets permissions (
chmod 770) and executes in background via/bin/zsh - Runs through
osascriptfor process-tree evasion
Windows (win32):
- Locates PowerShell via
where powershell - Copies it to
%PROGRAMDATA%\wt.exe(masquerading as Windows Terminal) - Writes a VBScript (
.vbs) to%TEMP%that:- Downloads a
.ps1payload from the C2 viacurl - Executes it hidden:
wt.exe -w hidden -ep bypass -file <payload>.ps1 - Deletes the
.ps1after execution
- Downloads a
- Runs the VBScript silently via
cscript //nologo, then deletes it
Linux (fallback):
- Downloads a Python script to
/tmp/ld.pyviacurl - Executes
python3 /tmp/ld.pyin background vianohup
The payload performs cleanup to hinder incident response:
- Self-deletion:
setup.jsremoves itself (fs.unlink(__filename)) - package.json swap: A clean
package.md(version 4.2.0, nopostinstallhook) is renamed topackage.json, overwriting the malicious version. Post-incident inspection ofnode_modules/plain-crypto-js/package.jsonwill show no trace of thepostinstalltrigger.
stq[0]: "child_process"
stq[1]: "os"
stq[2]: "fs"
stq[3]: "http://sfrclak.com:8000/"
stq[5]: "win32"
stq[6]: "darwin"
stq[7]: VBScript dropper (Windows)
stq[8]: "cscript \"LOCAL_PATH\" //nologo && del \"LOCAL_PATH\" /f"
stq[9]: AppleScript dropper (macOS)
stq[10]: "nohup osascript \"LOCAL_PATH\" > /dev/null 2>&1 &"
stq[12]: curl + python3 dropper (Linux)
stq[13]: "package.json"
stq[14]: "package.md"
stq[15]: ".exe"
stq[16]: ".ps1"
stq[17]: ".vbs"
axios is one of the most depended-upon packages in the npm ecosystem, with approximately 80 million weekly downloads. The compromised 1.14.1 was tagged as latest, and 0.30.4 was tagged as legacy. Any environment performing a fresh npm install of axios without a lockfile pinning a specific prior version would have pulled the backdoored release.
| Time | Event |
|---|---|
| 2026-02-18T17:19:20Z | axios@0.30.3 published legitimately by jasonsaayman@gmail.com |
| 2026-03-27T19:01:40Z | axios@1.14.0 published legitimately via GitHub Actions OIDC |
| 2026-03-31 | plain-crypto-js@4.2.0 and 4.2.1 published (brand-new package, attacker-controlled) |
| 2026-03-31T00:21:58Z | axios@1.14.1 published by compromised account; becomes latest |
| 2026-03-31T01:00:57Z | axios@0.30.4 published by compromised account; tagged legacy |
| 2026-03-31 | Discovered by Elastic Security researchers via automated supply-chain monitoring |
latest: 1.14.1 (COMPROMISED)
legacy: 0.30.4 (COMPROMISED)
old-version: 0.30.0 (legitimate)
next: 1.7.0-beta.2 (legitimate)
- npm registry: https://www.npmjs.com/package/axios
- npm registry: https://www.npmjs.com/package/plain-crypto-js
- axios GitHub: https://github.com/axios/axios




Thanks for your awesome work on this -- we are looking into it as well and the payload package was published by nrwise@proton.me, so there are at least 2 accounts involved here. Will share more as our agent digs deeper