Axios Supply Chain Attack — Security Check
Attack summary: On March 31, 2026, axios versions
and
were published via a compromised maintainer account. They silently injected
as a dependency, which ran a postinstall script deploying a cross-platform Remote Access Trojan (RAT). Both versions were removed by 03:29 UTC but may remain in local caches or lockfiles.
Run all four phases below and produce the report at the end.
Phase 1: Vulnerability Scan
Search for malicious axios versions in package manifests, lockfiles, and global caches.
1a. Project files under
Search for lockfiles and
files (limit depth to avoid excessive crawling):
bash
# Find package.json files containing axios (depth ≤ 8, skip .git and common noise)
find ~ -maxdepth 8 \
-not \( -path '*/.git/*' -o -path '*/node_modules/*/node_modules/*' \) \
-name "package.json" \
-exec grep -l '"axios"' {} \;
For each match, check if
is pinned to
or
:
bash
grep -E '"axios":\s*"[^"]*1\.14\.1|[^"]*0\.30\.4"' <path>/package.json
Search lockfiles for the malicious versions:
bash
# package-lock.json / yarn.lock / pnpm-lock.yaml / bun.lock
grep -r --include="package-lock.json" --include="yarn.lock" \
--include="pnpm-lock.yaml" --include="bun.lock" \
-l "axios" ~ 2>/dev/null | head -50
For each lockfile found:
bash
grep -A2 '"axios"' <lockfile> | grep -E "1\.14\.1|0\.30\.4"
1b. Global caches
Check global package manager caches for cached malicious tarballs:
bash
# npm cache
find ~/.npm/_cacache -name "*.json" 2>/dev/null | xargs grep -l '"axios"' 2>/dev/null | \
xargs grep -l '"1.14.1"\|"0.30.4"' 2>/dev/null
# pnpm store (macOS)
find ~/Library/pnpm/store -maxdepth 6 -name "package.json" 2>/dev/null | \
xargs grep -l '"axios"' 2>/dev/null | \
xargs grep -l '"1.14.1"\|"0.30.4"' 2>/dev/null
# pnpm store (Linux)
find ~/.local/share/pnpm/store -maxdepth 6 -name "package.json" 2>/dev/null | \
xargs grep -l '"axios"' 2>/dev/null | \
xargs grep -l '"1.14.1"\|"0.30.4"' 2>/dev/null
# bun cache
find ~/.bun/install/cache -maxdepth 6 -name "package.json" 2>/dev/null | \
xargs grep -l '"axios"' 2>/dev/null | \
xargs grep -l '"1.14.1"\|"0.30.4"' 2>/dev/null
Phase 2: Malware Artifact Check
2a. presence
The malicious dependency used as the attack vector:
bash
find ~ -maxdepth 10 -type d -name "plain-crypto-js" 2>/dev/null
Any result here means
was installed — the install-time RAT dropper ran.
2b. Platform-specific RAT artifacts
Check for files dropped by the RAT dropper. These are fixed paths.
macOS:
bash
ls -la /Library/Caches/com.apple.act.mond 2>/dev/null && echo "FOUND — potential RAT binary" || echo "Not found"
Linux:
bash
ls -la /tmp/ld.py 2>/dev/null && echo "FOUND — potential RAT script" || echo "Not found"
Windows (if running in WSL or checking a Windows path):
bash
ls -la /mnt/c/ProgramData/wt.exe 2>/dev/null && echo "FOUND — potential RAT binary" || echo "Not found"
2c. Active C2 connections
Check for live connections to the attacker's command-and-control server:
bash
# By IP
lsof -i @142.11.206.73 2>/dev/null || echo "No connections to C2 IP"
# By domain (if DNS resolves)
lsof -i 2>/dev/null | grep -i sfrclak || echo "No connections to sfrclak.com"
# By port 8000 (C2 port used)
lsof -i :8000 2>/dev/null | grep -v "localhost\|127\.0\.0" || echo "No suspicious :8000 connections"
Phase 3: Package Manager Security Audit
Detect which package managers are installed and check their security-relevant configuration. Read global config files and project-level config/manifest files in the current directory.
3a. Detect installed package managers
bash
which npm && npm --version
which pnpm && pnpm --version
which bun && bun --version
which yarn && yarn --version
3b. npm
Config files to read:
- Global:
- Project: in current directory
bash
npm config get ignore-scripts
npm config get min-release-age
npm config get audit
| Setting | Secure value | Default | Effect |
|---|
| | | Disables all lifecycle scripts for all packages |
| e.g. (3 days in seconds) | unset | Refuses to install package versions published more recently than the threshold — blocks day-zero malicious publishes |
| | | Checks installed packages against known vulnerability advisories |
Note: npm has no per-package script allowlist —
is all-or-nothing.
3c. pnpm
Config files to read:
- Global: (pnpm reads this too) and
- Project: ,
- → field
bash
pnpm config get ignore-scripts 2>/dev/null
pnpm config get ignoreDepScripts 2>/dev/null
pnpm config get minimumReleaseAge 2>/dev/null
pnpm config get blockExoticSubdeps 2>/dev/null
pnpm config get onlyBuiltDependencies 2>/dev/null
pnpm config get neverBuiltDependencies 2>/dev/null
pnpm config get strictDepBuilds 2>/dev/null
pnpm config get dangerouslyAllowAllBuilds 2>/dev/null
Also read project-level files:
bash
cat pnpm-workspace.yaml 2>/dev/null | grep -E "minimumReleaseAge|blockExoticSubdeps|onlyBuiltDependencies|allowBuilds|neverBuiltDependencies|strictDepBuilds|ignoreDepScripts|dangerouslyAllowAllBuilds"
cat package.json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps(d.get('pnpm',{}), indent=2))" 2>/dev/null
| Setting | Secure value | Default | Effect |
|---|
| e.g. (1 day, in minutes) | | Refuses packages published more recently than the threshold — blocks day-zero attacks like this one |
| scoped list | unset | Packages exempt from the age check |
| | | Transitive deps must come from a registry; blocks git/tarball URL subdependencies injected by attackers |
| | | Skips lifecycle scripts in dependencies only; project scripts still run |
| | | Skips all lifecycle scripts (dependencies and project) |
| Explicit allowlist | unset | Only listed packages may run install scripts — all others blocked |
| Per-package map | unset | Newer alternative to ; supports version constraints and explicit entries |
| Blocklist of known-bad packages | unset | Explicitly prevents listed packages from running scripts |
| | | Install fails if any dependency has unreviewed build scripts — forces explicit approval |
dangerouslyAllowAllBuilds
| | | Flag if this is — it bypasses all script controls |
3d. bun
Config files to read:
- Global:
- Project:
- Project → field
bash
cat ~/.bunfig.toml 2>/dev/null || echo "No global bunfig.toml"
cat bunfig.toml 2>/dev/null || echo "No project bunfig.toml"
cat package.json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps(d.get('trustedDependencies','not set'), indent=2))" 2>/dev/null
| Setting | Location | Secure value | Default | Effect |
|---|
| | Explicit allowlist | Top-500 npm packages auto-trusted | Only listed packages may run lifecycle scripts; any package not on this list is blocked |
[install].minimumReleaseAge
| | e.g. (seconds) | unset | Refuses packages newer than the threshold |
[install].lifecycle-scripts
| | Scoped allowlist | unset | Alternative/additional script execution control |
Note: Bun's default is more secure than npm — scripts are blocked for packages not in the built-in top-500 allowlist. An explicit
field in
overrides this and should be reviewed carefully.
3e. Yarn (Berry)
Config files to read:
bash
cat ~/.yarnrc.yml 2>/dev/null | grep -E "enableScripts|dependenciesMeta" || echo "No global .yarnrc.yml"
cat .yarnrc.yml 2>/dev/null | grep -E "enableScripts|dependenciesMeta" || echo "No project .yarnrc.yml"
| Setting | Secure value | Default | Effect |
|---|
| | | Disables all lifecycle scripts globally; re-enable per-package via |
3f. CI/CD workflow check
If
exists, check install commands for hardening flags:
bash
grep -r --include="*.yml" --include="*.yaml" \
-E "npm install|npm ci|pnpm install|bun install|yarn install" \
.github/ 2>/dev/null | head -20
Flags to look for:
,
(vs
),
.
Phase 4: Report
Produce a clean report with the following structure. Be explicit about each finding — "not found" is a valid and important result.
## Axios Supply Chain Attack — Security Report
Generated: <date>
### Vulnerability Scan
- Affected axios versions found in project files: <list paths or "None found">
- Affected axios versions found in global caches: <list or "None found">
### Malware Artifacts
- plain-crypto-js present: <Yes — <path> | No>
- macOS RAT binary (/Library/Caches/com.apple.act.mond): <Found | Not found>
- Linux RAT script (/tmp/ld.py): <Found | Not found>
- Windows RAT binary (%PROGRAMDATA%\wt.exe): <Found | Not found>
- Active C2 connections (sfrclak.com:8000 / 142.11.206.73): <Active | None detected>
### Package Manager Security Audit
For each installed package manager, report the key settings. Use "✓ set", "✗ unset", or the actual value.
**npm <version>:**
- `ignore-scripts`: <value>
- `min-release-age`: <value or "not set">
- `audit`: <value>
**pnpm <version>:**
- `minimumReleaseAge`: <value or "not set">
- `blockExoticSubdeps`: <value>
- `ignoreDepScripts`: <value>
- `onlyBuiltDependencies` / `allowBuilds`: <set with N packages | not set>
- `strictDepBuilds`: <value>
- `dangerouslyAllowAllBuilds`: <value — flag if true>
**bun <version>:**
- `trustedDependencies` in package.json: <explicit list | using defaults>
- `[install].minimumReleaseAge` in bunfig.toml: <value or "not set">
**yarn <version>:**
- `enableScripts`: <value or "not set (defaults to true)">
### Recommendations
[Prioritized list based on findings above — see guidance below]
Recommendation guidance (include relevant items only)
If compromised (artifacts found or C2 connections detected):
- Treat as full system breach — isolate immediately
- Rotate all credentials: API keys, SSH keys, cloud credentials, npm tokens, GitHub tokens
- Rebuild from a clean snapshot if possible
- Review logs for C2 traffic to / between March 31 00:00–04:00 UTC 2026
If malicious axios version found (no artifacts):
- Remove from lockfile: downgrade to (last safe 1.x) or (last safe 0.x)
- Delete from and lockfile
- Run fresh install: / /
For pnpm users:
- Set in — even 24h (1440 min) would have blocked this attack, which published and was removed within ~3 hours:
yaml
minimumReleaseAge: 1440 # 1 day in minutes
- Enable — the injected could have been delivered via tarball URL; this blocks non-registry transitive deps:
- Use or to allowlist only packages that legitimately need scripts. Prefer (pnpm 9+) as it supports version constraints:
yaml
# pnpm-workspace.yaml
onlyBuiltDependencies:
- esbuild
- sharp
- "@swc/core"
- Enable so installs fail loudly if an unknown package tries to run scripts:
- Use if you need to run your own project scripts but want to block all dependency scripts (more surgical than )
- Verify
dangerouslyAllowAllBuilds
is not set to — if it is, remove it immediately
For npm users:
- Set in — this is the single most effective preventive control for day-zero attacks:
(259200 seconds = 3 days; even 3600 = 1 hour would have blocked this attack)
- Add to for CI environments (may break packages with legitimate build steps — test first)
- Use instead of in CI — it respects lockfiles exactly and fails on drift
- Run
npm audit --audit-level=high
in CI pipelines
For bun users:
- Set an explicit in rather than relying on bun's default top-500 list. Review which packages in your dependency tree genuinely need scripts:
json
{
"trustedDependencies": ["esbuild", "sharp"]
}
- Set in :
toml
[install]
minimumReleaseAge = 259200 # 3 days in seconds
For yarn users (Berry):
- Add to :
- Re-enable per package via for packages with legitimate build scripts
General (all users):
- Always commit lockfiles to version control — they are the source of truth for installed versions
- Use / flags in CI to prevent lockfile drift
- Consider Socket.dev or Snyk for continuous supply chain monitoring that catches malicious packages before they install