On March 31, 2026, StepSecurity identified two malicious versions of axios, one of the most widely used JavaScript HTTP client libraries, published to npm via a compromised lead maintainer account: [email protected] and [email protected]. Both versions inject a rogue dependency, [email protected], that executes a cross-platform RAT dropper on npm install. The attack bypassed axios's GitHub Actions CI/CD pipeline entirely; the attacker hijacked the maintainer account, changed the email to an anonymous ProtonMail address, and published manually via the npm CLI. Any developer or CI system that ran npm install with these versions should assume compromise.

What Happened

The attack was pre-staged across roughly 18 hours with deliberate operational security:

Neither poisoned version contains malicious code inside axios itself. The malware is entirely inside [email protected], which is never imported by axios's source code; it exists solely to execute at install time.

What Was Taken

The dropper contacts a live C2 server (sfrclak.com / 142.11.206.73) and delivers platform-specific second-stage payloads:

After execution, the malware deletes itself and replaces its own package.json with a clean decoy. A developer inspecting node_modules after the fact will find no visible evidence of the malicious dependency.

The second-stage RAT payloads provide persistent remote access. Full capability analysis is ongoing. At minimum, assume: credential theft, environment variable exfiltration (including CI secrets, API keys, tokens), and potential lateral movement from any compromised developer workstation or CI runner.

Why It Matters

axios has 50+ million weekly npm downloads. This is not a niche package. It is a direct or transitive dependency in a substantial fraction of Node.js applications, build pipelines, and CI environments globally.

The attack model defeats standard CI security controls. By publishing via the npm CLI with compromised credentials rather than through GitHub Actions, the attacker bypassed the project's automated publishing safeguards. Package signing alone does not help here; the package was legitimately signed by the real maintainer's (compromised) account.

The pre-staging is sophisticated. Publishing a clean decoy version of plain-crypto-js 18 hours before the attack to establish publishing history is a deliberate counter-detection step. This is not opportunistic; it mirrors the TeamPCP methodology used against Trivy and the Telnyx SDK earlier this week.

Self-destruction on execution. The malware actively removes forensic evidence after running. Post-infection inspection of node_modules will not reveal compromise. The only reliable detection signals are network-level (C2 connections to sfrclak.com) and filesystem-level (checking for the dropped files).

CI runners are the primary blast radius. Any CI/CD system that runs npm install without a lockfile pinning or integrity check, including GitHub Actions, GitLab CI, Jenkins, CircleCI, may have executed the dropper with elevated permissions and access to secrets injected as environment variables.

The Attack Technique

  1. Account takeover: Lead maintainer jasonsaayman account compromised; email swapped to [email protected] to sever GitHub Actions publish verification
  2. Dependency injection: [email protected] listed as a new runtime dependency in [email protected] and 0.30.4
  3. Postinstall execution: npm runs node setup.js automatically on package install; no user interaction required
  4. Obfuscated dropper: setup.js identifies the host OS, contacts C2, pulls and executes platform-specific second-stage payload
  5. Self-erasure: Malware deletes setup.js and writes a clean package.json over itself to evade post-infection detection

IOCs

Type Indicator
Malicious packages [email protected], [email protected], [email protected]
C2 domain sfrclak.com
C2 IP 142.11.206.73
macOS file /Library/Caches/com.apple.act.mond
Windows file %PROGRAMDATA%\wt.exe
Linux file /tmp/ld.py

What Organizations Should Do

  1. Scan all lockfiles immediately. Run grep -r "1.14.1\|0.30.4" package-lock.json yarn.lock across every repository, including transitive dependencies. Check for plain-crypto-js anywhere in your dependency trees.

  2. If found, assume full compromise. Rotate all secrets, API keys, tokens, and credentials accessible from affected machines or CI environments. This includes environment variables injected into CI runners, SSH keys, cloud credentials, and npm tokens.

  3. Block C2 at the network perimeter. Immediately block sfrclak.com and 142.11.206.73 at your egress firewall or DNS resolver. Check historical DNS and network logs for connections to these indicators from dev machines and CI systems.

  4. Check for dropped files on all developer machines and CI runners. Look for /Library/Caches/com.apple.act.mond (macOS), %PROGRAMDATA%\wt.exe (Windows), /tmp/ld.py (Linux). Presence confirms execution.

  5. Pin to safe versions. [email protected] (1.x branch) or [email protected] (0.x branch) are clean. Update lockfiles and commit.

  6. Enforce lockfile integrity in CI. Use npm ci (not npm install) in all CI pipelines; it installs from the lockfile and fails if the lockfile doesn't match. Enable npm audit as a gate. Consider Artifact Transparency tools (Socket, StepSecurity Harden-Runner) to detect new transitive dependencies at publish time.

Sources