# Security Axios

> Scan ALL projects on this Mac for the axios supply-chain attack (2026-03-31). Detects compromised versions (axios@1.14.1, axios@0.30.4), malicious dependency (plain-crypto-js@4.2.1), related campaign packages (@shadanai/openclaw, @qqbrowser/openclaw-qbot), and macOS RAT IOC (/Library/Caches/com.apple.act.mond) with SHA256 verification. Scans package.json, package-lock.json, yarn.lock, and pnpm-lock.yaml. Checks launch persistence and dropper anti-forensics. Generates an HTML report and opens it in the default browser. Use when the user says "scan for axios attack", "check axios supply chain", "axios malware scan", "am I affected by axios compromise", or "security-axios".

- Skill: `bgauryy/security-axios` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add bgauryy/security-axios`
- Raw SKILL.md: https://api.skillmd.com/api/skills/bgauryy/security-axios/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Marketing & Growth
- Author: bgauryy (https://skillmd.com/u/bgauryy)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/bgauryy/security-axios

---


# Security: Axios Supply-Chain Attack Scanner

## Mission

Scan the entire Mac for the axios npm supply-chain compromise (2026-03-31).
Check `package.json` **and all lock files** (`package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`).
Detect anti-forensics (dropper self-cleanup), related campaign packages, and verify RAT SHA256.
Produce a full HTML threat report and open it automatically.

## Background

On 2026-03-31, axios versions **1.14.1** and **0.30.4** were published via a compromised maintainer
account (`jasonsaayman`, email changed to `ifstap@proton.me`) with an injected dependency
`plain-crypto-js@4.2.1`. Its postinstall hook (`setup.js`) deployed a cross-platform RAT that
beacons to `sfrclak[.]com:8000` every 60 seconds. On macOS the RAT binary is
`/Library/Caches/com.apple.act.mond`. The dropper self-destructs after execution: `setup.js` is
deleted and `package.json` is replaced with a clean stub reporting version `4.2.0` — so
post-infection `node_modules` inspection will NOT reveal the malicious manifest. The directory
presence of `node_modules/plain-crypto-js/` alone confirms the dropper ran.

The malicious dependency was pre-staged ~18 hours earlier by attacker account `nrwise`
(`nrwise@proton.me`). A clean decoy version (`4.2.0`) was published first to build registry history.
Both compromised axios versions were published manually with a stolen npm token — no OIDC Trusted
Publisher binding, no `gitHead`, no corresponding GitHub commit or tag.

---

## References

| Source | URL |
|---|---|
| Snyk Advisory | https://snyk.io/blog/axios-npm-package-compromised-supply-chain-attack-delivers-cross-platform/ |
| Wiz Blog | https://www.wiz.io/blog/axios-npm-compromised-in-supply-chain-attack |
| StepSecurity Blog | https://www.stepsecurity.io/blog/axios-compromised-on-npm-malicious-versions-drop-remote-access-trojan |
| Aikido Blog | https://www.aikido.dev/blog/axios-npm-compromised-maintainer-hijacked-rat |
| GitHub Issue #10604 | https://github.com/axios/axios/issues/10604 |
| GitHub Advisory | https://github.com/advisories/GHSA-fw8c-xr5c-95f9 |
| OSV Advisory | https://osv.dev/vulnerability/MAL-2026-2306 |
| Elastic Security Gist | https://gist.github.com/joe-desimone/36061dabd2bc2513705e0d083a9673e7 |

---

## Threat Intelligence

| Category | Value |
|---|---|
| Compromised axios versions | `1.14.1`, `0.30.4` |
| Malicious dependency | `plain-crypto-js@4.2.1` |
| Related campaign packages | `@shadanai/openclaw` (v2026.3.28-2, 2026.3.28-3, 2026.3.31-1, 2026.3.31-2), `@qqbrowser/openclaw-qbot` (v0.0.130) |
| macOS RAT binary | `/Library/Caches/com.apple.act.mond` |
| macOS RAT SHA256 | `92ff08773995ebc8d55ec4b8e1a225d0d1e51efa4ef88b8849d0071230c9645a` |
| Windows RAT | `%PROGRAMDATA%\wt.exe` (PowerShell copy), `%TEMP%\6202033.ps1`, `%TEMP%\6202033.vbs` |
| Windows RAT SHA256 | `617b67a8e1210e4fc87c92d1d1da45a2f311c08d26e89b12307cf583c900d101` (PS1) |
| Linux RAT | `/tmp/ld.py` |
| Linux RAT SHA256 | `fcb81618bb15edfdedfb638b4c08a2af9cac9ecfa551af135a8402bf980375cf` |
| C2 domain | `sfrclak[.]com` |
| C2 IP | `142.11.206.73` |
| C2 port | `8000` |
| Campaign path | `/6202033` |
| C2 POST body (macOS) | `packages.npm.org/product0` |
| C2 POST body (Windows) | `packages.npm.org/product1` |
| C2 POST body (Linux) | `packages.npm.org/product2` |
| Infection vector | `npm install` / `yarn install` / `pnpm install` postinstall hook |
| Compromised account | `jasonsaayman` (email changed to `ifstap@proton.me`) |
| Attacker account | `nrwise` (`nrwise@proton.me`) — published `plain-crypto-js` |
| GitHub Advisory | GHSA-fw8c-xr5c-95f9 |
| OSV Advisory | MAL-2026-2306 |
| Attack window | 2026-03-31 00:21–03:15 UTC (~3 hours) |
| Windows persistence | Registry Run key `MicrosoftUpdate`, re-download batch file |
| macOS dropper method | AppleScript via `osascript` writing to `/tmp/6202033` |

### Package SHA256 Hashes

| Package | SHA256 |
|---|---|
| `axios-1.14.1.tgz` | `5bb67e88846096f1f8d42a0f0350c9c46260591567612ff9af46f98d1b7571cd` |
| `axios-0.30.4.tgz` | `59336a964f110c25c112bcc5adca7090296b54ab33fa95c0744b94f8a0d80c0f` |
| `plain-crypto-js-4.2.1.tgz` | `58401c195fe0a6204b42f5f90995ece5fab74ce7c69c67a24c61a057325af668` |
| `com.apple.act.mond` (macOS) | `92ff08773995ebc8d55ec4b8e1a225d0d1e51efa4ef88b8849d0071230c9645a` |
| `stage2.ps1` (Windows) | `617b67a8e1210e4fc87c92d1d1da45a2f311c08d26e89b12307cf583c900d101` |
| `ld.py` (Linux) | `fcb81618bb15edfdedfb638b4c08a2af9cac9ecfa551af135a8402bf980375cf` |

### Package SHA1 Shasums (npm)

| Package | SHA1 |
|---|---|
| `axios@1.14.1` | `2553649f232204966871cea80a5d0d6adc700ca` |
| `axios@0.30.4` | `d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71` |
| `plain-crypto-js@4.2.1` | `07d889e2dadce6f3910dcbc253317d28ca61c766` |

---

## Anti-Forensics Awareness

The dropper (`setup.js`) performs three cleanup actions after execution:

1. **Deletes `setup.js`** — `fs.unlink(__filename)` removes itself
2. **Deletes `package.json`** — removes the manifest with `"postinstall": "node setup.js"`
3. **Renames `package.md` to `package.json`** — a pre-staged clean stub reporting version `4.2.0`

**Post-infection, `npm list` shows `plain-crypto-js@4.2.0`** (not `4.2.1`). Incident responders
checking for version `4.2.1` may incorrectly conclude the system is clean. The reliable check is
**directory presence**: if `node_modules/plain-crypto-js/` exists at all, the dropper ran — this
package is not a dependency of ANY legitimate axios version.

Our scanner checks:
- `node_modules/plain-crypto-js/` directory existence (confirms dropper ran)
- `node_modules/plain-crypto-js/setup.js` presence (dropper not yet cleaned up)

---

## Execution Flow

```
GREP PRE-FILTER → PARSE → LOCK FILES → RELATED PKGS → IOC CHECK → SHA256 VERIFY → LAUNCH PERSIST → REPORT → OPEN
```

---

## What Is Scanned

| File / Check | What We Check |
|---|---|
| `package.json` | declared axios version, plain-crypto-js in all dep sections, related campaign packages |
| `package-lock.json` | resolved axios version, plain-crypto-js in packages tree, related campaign packages |
| `yarn.lock` | resolved axios version, any mention of plain-crypto-js |
| `pnpm-lock.yaml` | resolved axios version, any mention of plain-crypto-js |
| `node_modules/plain-crypto-js/` | directory presence (confirms dropper ran even after self-cleanup) |
| `node_modules/plain-crypto-js/setup.js` | dropper file still present (not yet cleaned up) |
| `/Library/Caches/com.apple.act.mond` | RAT binary present + SHA256 hash verification against known IOC |
| running processes via `pgrep` | RAT process (FP-safe — pgrep excludes itself) |
| `lsof -i` | active C2 connection to sfrclak.com or 142.11.206.73 |
| `~/Library/LaunchAgents/`, `/Library/LaunchAgents/`, `/Library/LaunchDaemons/` | launch persistence referencing act.mond, sfrclak, or C2 IP |
| global npm/yarn/pnpm | plain-crypto-js installed globally |

---

## False-Positive Notes

**Process check FP risk**: NEVER use `ps aux | grep act.mond` — a bash heredoc containing that string
would match itself. Use `pgrep -f "/Library/Caches/com.apple.act.mond"` instead — pgrep excludes
its own PID, and the script runs as `python3 /tmp/file.py` (no script content in command line).

**Anti-forensics version mismatch**: After dropper cleanup, `npm list plain-crypto-js` reports
`4.2.0` (not `4.2.1`). The scanner checks directory existence rather than version number.

---

## Scripts

The scanner is split into focused modules under `scripts/`:

```
skills/security-axios/scripts/
├── axios_scan.py    # Entry point — orchestrates scan, IOC check, report
├── constants.py     # Threat intel: IOC hashes, versions, references, skip dirs
├── scanners.py      # Manifest/lock file parsers + find_and_scan walker
├── ioc_check.py     # System IOC checks: RAT, C2, globals, launch persistence
└── report.py        # HTML report generation: CSS, tables, badges, template
```

To run:

```bash
python3 /Users/guybary/Documents/skills/skills/security-axios/scripts/axios_scan.py
```

---

## Module Reference

### `constants.py` — Threat Intelligence Data

All IOC constants, SHA256 hashes, related campaign packages, skip directories, and reference URLs.

### `scanners.py` — Manifest & Lock File Parsers

| Function | Purpose |
|---|---|
| `scan_package_json(path)` | Scan for axios, plain-crypto-js, and related campaign packages in all dep sections |
| `scan_package_lock(path)` | Scan npm lockfile v1/v2/v7+ packages tree, including related packages |
| `scan_yarn_lock(path)` | Regex-based scan for compromised resolved versions |
| `scan_pnpm_lock(path)` | Regex-based scan for pnpm lockfile v5/v6/v9 formats |
| `find_and_scan()` | Walk `~/`, merge findings per repo, track dropper evidence (`plain_installed`, `setup_js_present`) |
| `quick_hit(path, *needles)` | Bytes-level grep pre-filter before full parse |
| `check_related_pkgs(all_deps)` | Check dependency map for `@shadanai/openclaw`, `@qqbrowser/openclaw-qbot` |

### `ioc_check.py` — System IOC Detection

| Function | Purpose |
|---|---|
| `check_iocs()` | Returns `(rat_found, rat_hash_match, rat_running, c2_active, global_crypto, launch_persist)` |
| `sha256_file(path)` | Compute SHA256 for IOC hash verification |

Checks performed:
- RAT binary existence + SHA256 verification against known hash
- `pgrep -f` for running RAT process (FP-safe)
- `lsof -i` for active C2 connections
- npm/yarn/pnpm global list for `plain-crypto-js`
- LaunchAgents/LaunchDaemons scan for persistence references

### `report.py` — HTML Report Generation

Generates dark-themed HTML report with:
- Threat intel section (SHA256 hashes, campaign path, advisory IDs)
- Project tables with dropper evidence and related packages columns
- Source badges (📦 package.json · 🔒 lockfile · 🧶 yarn · ⚡ pnpm)
- References & Advisories section with all 8 source links
- Remediation steps including version pinning and CI/CD `--ignore-scripts`
- Footer with advisory links (GHSA, OSV, Snyk, Wiz, StepSecurity, Aikido)

---

## Execution Instructions

When this skill is invoked:

1. **Announce** — scanning for the axios supply-chain attack (2026-03-31).

2. **Run the scanner script directly** — do NOT copy/paste inline:

```bash
python3 /Users/guybary/Documents/skills/skills/security-axios/scripts/axios_scan.py
```

3. **What the script does**:
   - Walk `~/` skipping `node_modules`, `Library`, caches, etc.
   - Use bytes-level grep pre-filter before full JSON/YAML parsing (fast)
   - Scan `package.json`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml` per repo
   - Check for related campaign packages (`@shadanai/openclaw`, `@qqbrowser/openclaw-qbot`)
   - Detect dropper anti-forensics (directory presence vs `setup.js` presence)
   - Check macOS IOC with `pgrep -f RAT_PATH` (NOT `ps aux | grep` — avoids FP)
   - SHA256 verify RAT binary against known hash `92ff0877...c9645a`
   - Check C2 connections via `lsof -i`
   - Check global npm/yarn/pnpm for `plain-crypto-js`
   - Scan LaunchAgents/LaunchDaemons for persistence referencing attack IOCs
   - Generate dark-themed HTML with source badges (📦 🔒 🧶 ⚡) and all references
   - Open in browser automatically

4. **Print the terminal summary**.

5. **Verdict**:
   - `🚨 SYSTEM COMPROMISED` — RAT binary / C2 active / launch persistence
   - `⚠ VULNERABLE DEPS FOUND` — compromised axios in lock files / package.json
   - `✅ CLEAN` — no compromised versions, no IOCs

6. **List each compromised repo** with path, version, which file(s) confirmed it, and related packages.

---

## Constraints

- NEVER output credential values from any scanned file.
- NEVER modify any files. Read-only scan.
- Skip `node_modules/` when walking for manifests.
- FP rule: use `pgrep -f RAT_PATH` — never `ps aux | grep act.mond`.

---

## Success Criteria

- [ ] All `package.json` + lock files scanned (outside `node_modules`)
- [ ] Compromised axios `1.14.1` / `0.30.4` detected in package.json AND lock files
- [ ] `plain-crypto-js@4.2.1` detected in all manifest types
- [ ] Related campaign packages (`@shadanai/openclaw`, `@qqbrowser/openclaw-qbot`) detected
- [ ] yarn.lock and pnpm-lock.yaml scanned for resolved versions
- [ ] Anti-forensics detected (plain-crypto-js directory presence + setup.js check)
- [ ] macOS RAT IOC checked (binary + SHA256 verification + pgrep process + lsof C2)
- [ ] Launch persistence checked (LaunchAgents/LaunchDaemons)
- [ ] Global npm/yarn/pnpm checked for plain-crypto-js
- [ ] HTML report with source badges (📦 package.json · 🔒 lockfile · 🧶 yarn · ⚡ pnpm)
- [ ] HTML report includes all 8 references (Snyk, Wiz, StepSecurity, Aikido, GitHub Issue, GHSA, OSV, Elastic)
- [ ] HTML report includes SHA256 hashes and advisory IDs in threat intel section
- [ ] Report auto-opened in browser
- [ ] No false positives from process detection

