Axios isn’t just a popular npm package. It’s infrastructure. Frontend apps, backend APIs, CI/CD pipelines, enterprise tooling, open source projects that power critical software you use every day. It gets downloaded roughly 100 million times a week.1 If you’ve written JavaScript in the last five years, it’s almost certainly somewhere in your dependency tree right now, probably three or four layers deep, somewhere you’d never think to look.

On March 31, 2026, someone poisoned it.2

How It Went Down

The attack started at least 18 hours before anyone noticed a thing. The attacker’s first move was patience. They published a package called plain-crypto-js@4.2.0 to the npm registry. Clean. Harmless.2 Nothing in it. The whole point was to get it aged into the registry so that automated security scanners wouldn’t flag it as a brand-new package when it mattered. That’s the kind of planning that should make you uncomfortable.

When the time came, they compromised the npm account for jasonsaayman, the primary axios maintainer. The account’s registered email got swapped to a Proton Mail address they controlled. Then, within a 39-minute window, two malicious axios versions hit the registry: axios@1.14.1 and axios@0.30.4.3 Both major release branches. Covered.

Neither of those releases contained malicious code inside axios itself. That’s what made it clean. Both simply added plain-crypto-js@4.2.1 as a runtime dependency. That’s the version they’d just published minutes earlier with the actual payload baked in.

Two Seconds

Here’s the sequence when someone ran npm install on a poisoned axios version:

plain-crypto-js@4.2.1 fired a postinstall script. Within two seconds of install starting, it reached out to a C2 server at sfrclak.com:8000.2 It downloaded a second-stage payload, pre-built for Windows, macOS, and Linux separately. Executed it. Then it deleted itself, swapped its own package.json for a clean decoy, and vanished from node_modules.2

A developer who went looking after the fact would find nothing wrong.

That wasn’t a side effect. It was the design.

The attacker built the self-destruct specifically so you couldn’t find evidence. Which means the absence of evidence is not reassuring here. It’s the whole point.

How It Got Caught

It got caught because of runtime monitoring in a CI environment, not because anyone found something suspicious in a package.

StepSecurity’s Harden-Runner monitors GitHub Actions workflows at runtime across 12,000+ public repositories.2 During a CI run in the Backstage project, it detected an unexpected outbound network connection to sfrclak.com:8000. That domain had never shown up in any prior Backstage workflow run. The Backstage team confirmed their environment was sandboxed and nothing was exfiltrated. But the detection documented the live C2 callback in real time, and that was enough to pull the thread.

This is the concrete case for runtime monitoring that people keep abstracting into principle. You can audit packages all you want. If the malware runs and then destroys its own evidence, static analysis after the fact won’t save you. Something watching the network in the moment will.

The Access Control Problem

When the axios team found out about the breach, a collaborator tried to revoke the attacker’s access. Couldn’t do it.4 The compromised jasonsaayman account had higher permissions than the collaborator’s own account. The attacker was effectively locked in until npm itself intervened.

Think about that. An attacker who steals the right credential doesn’t just get to publish. They get to stay. The access control model didn’t have a clean path for a lower-privileged collaborator to eject a compromised owner account. That’s a structural gap, not a procedural one.

Both malicious axios versions and plain-crypto-js@4.2.1 have been removed from npm. The safe versions are axios@1.14.0 and axios@0.30.3.2

What You Need to Do Right Now

If you ran npm install during the affected window and got axios@1.14.1 or axios@0.30.4, rotate everything. API keys, tokens, environment variables, service credentials. All of it.

Not because you’ll find evidence you were hit. You probably won’t. Rotate because the payload was designed to prevent you from knowing whether you were hit. That’s the entire threat model here. You have to assume compromise and act accordingly.

Check your lock files. Check your CI logs. If you’ve got runtime network monitoring, pull those logs for the affected window and look for any connections to sfrclak.com.

This Isn’t New. But This Is Different.

This month, gNerdSEC has covered a run of npm supply chain attacks that would normally look alarming on their own: PhantomRaven in March, the Ghost Campaign targeting credential theft, TeamPCP and CanisterWorm, GlassWorm using blockchain-based C2 infrastructure to hit Solana developers. Each one was serious.

But every one of those attacks targeted fake packages, typosquats, or niche libraries with limited blast radius. The attacker had to get developers to install something they probably wouldn’t install otherwise.

This attack skipped that problem entirely. Axios already has 100 million downloads a week. The attacker didn’t need to trick anyone into installing anything new. They just needed one credential.

The Real Takeaway

npm’s trust model is built on maintainer accounts. That’s it. That’s the whole thing. When you run npm install, you’re trusting that the people who published those packages are who they say they are and that their accounts haven’t been compromised. There’s no code signing enforced at the registry level. No mandatory MFA for publishing. Just an account and a password and whatever authentication the maintainer chose.

One compromised credential on a sufficiently popular package is enough to reach millions of developers in a single afternoon. And if the attacker is careful about it, nobody finds a trace.

Your build pipeline is only as secure as the weakest npm account in your dependency graph. Not your direct dependencies. The whole graph. Including the packages you’ve never heard of that power the packages you use every day.

Axios just made that concrete.


  1. npm package page showing current axios latest version - https://www.npmjs.com/package/axios 

  2. StepSecurity primary incident write-up with timeline and behavior details - https://www.stepsecurity.io/blog/axios-compromised-on-npm-malicious-versions-drop-remote-access-trojan  2 3 4 5 6

  3. Socket analysis of malicious dependency injection and release flow anomalies - https://socket.dev/blog/axios-npm-package-compromised 

  4. axios GitHub issue #10604 discussing compromise response - https://github.com/axios/axios/issues/10604