a computer on a desk
Security
admin  

Not in axios’s source — a hijacked maintainer account pushed a phantom dependency that installed a cross‑platform RAT

On March 31, 2026, attackers used a hijacked npm maintainer account to publish poisoned axios releases that exercised npm’s install lifecycle, not by altering axios source code but by adding a phantom dependency (plain-crypto-js@4.2.1) whose postinstall hook deployed a cross‑platform remote access trojan (RAT). The publication used stolen long‑lived npm tokens to bypass GitHub Actions OIDC Trusted Publisher checks, so the releases had no corresponding commits or tags in the axios GitHub repository.

March 31 timeline: staging, publish, and takedown

The malicious sequence began with a staged publication of plain-crypto-js: a clean decoy 4.2.0 was pushed first to build history, then 4.2.1 with an obfuscated postinstall dropper appeared roughly 18–24 hours later. On March 31, 2026 the attacker published axios@1.14.1 and axios@0.30.4 that declared plain-crypto-js as a runtime dependency; npm removed those malicious axios packages about 3 hours and 19 minutes after publication.

Stage Marker / time Concrete effect
Staging (decoy) 4.2.0 published (prehistory) Avoided zero‑history alerts on npm
Malicious package plain-crypto-js@4.2.1 (postinstall) Executed setup.js dropper contacting sfrclak.com:8000
Poisoned axios publish axios@1.14.1 & axios@0.30.4 (Mar 31, 2026) npm install ran phantom dependency postinstall on hosts/CI
Removal ~3 hours 19 minutes later npm removed packages and replaced dependency with stub

What the phantom dependency actually executed

plain-crypto-js@4.2.1 contained a minified setup.js run from an npm postinstall hook; it contacted a live C2 server at sfrclak.com:8000, downloaded OS‑specific binary stages (Windows, macOS Mach‑O universal, Linux ELF), and then erased or replaced its package.json to look benign. The RAT harvested credentials, fingerprinted systems, and set persistence: on Windows via a Run registry entry pointing to a hidden batch loader, on macOS via a Mach‑O file placed in a system cache path, and on Linux via a tailored binary placed in a hidden directory.

Exfiltrated data was encrypted with AES‑256‑CBC and wrapped with RSA‑4096 before transmission; the implant beaconed the C2 every 60 seconds. Because plain-crypto-js was added to package.json but never imported by axios, static analysis of application code could miss it entirely while npm lifecycle scripts triggered execution during install.

How CI/CD and token practices were exploited

The attacker replaced the maintainer’s registered email with a ProtonMail address and used stolen long‑lived npm tokens to publish the poisoned releases manually. That allowed the actor to sidestep GitHub Actions OIDC Trusted Publisher protections, which depend on short‑lived tokens tied to verified workflows; the poisoned axios releases had no matching commits or tags in the official GitHub repo, a clear forensic sign of a manual publish.

Standard SCA and CVE‑feed scanners failed here because they look for known vulnerable code or flagged packages; lifecycle hooks and phantom runtime dependencies evade those signals. Detection in this incident came from behavioral monitoring: StepSecurity’s Harden‑Runner flagged unexpected outbound connections to sfrclak.com during CI runs in projects like Backstage, prompting investigation and the subsequent npm takedown.

Practical checkpoints and limits for maintainers and infra teams

Immediate operational checkpoints: rotate and revoke any long‑lived npm tokens used by maintainers, audit all CI runners that ran npm install during the 3‑hour‑19‑minute exposure window, and treat secrets present on those runners as potentially exfiltrated. Enforce least privilege for tokens, prefer OIDC short‑lived credentials, and require token expiration and scoped access for package publishing.

a person giving a presentation

Network and behavioral controls that change the attacker’s calculus include CI egress restrictions (block outbound connections by default), runtime behavioral monitoring for unexpected callbacks (as StepSecurity Harden‑Runner demonstrated), and automated inspections of package-lock changes that introduce dependencies with no upstream import or repository history. Note the practical limit: even with these controls, an attacker who publishes via a legitimate maintainer account can reach developer machines where npm install runs with user credentials or mounted secrets.

Short Q&A

Should teams rotate npm tokens immediately? Yes — revoke any long‑lived tokens tied to the compromised maintainer and rotate secrets exposed on CI during the exposure window.

Does this mean axios’s source repo was modified? No — the malicious activity came from a phantom dependency and postinstall hooks executed during npm install; axios GitHub commits and tags did not match the published malicious releases.

How can I detect similar phantom dependencies? Combine lockfile inspections for new transitive packages, CI network egress monitoring for unknown domains, and behavioral runners that flag unexpected outbound connections during builds.

Leave A Comment