How the Axios NPM Hijack Actually Worked — and What Stops the Next One

5 min read 1 source explainer
├── "NPM's publish-time verification is fundamentally broken and enables repeated supply chain attacks"
│  ├── StepSecurity (StepSecurity Blog) → read

StepSecurity's research team identified and documented the full attack chain, showing how malicious versions of Axios were published containing a RAT. Their analysis demonstrates that a single compromised publishing token was sufficient to push arbitrary code to millions of machines, with no code review, diff analysis, or behavioral sandboxing at publish time.

│  └── top10.dev editorial (top10.dev) → read below

The editorial argues that NPM's registry confirms only that a publishing token is valid and the version number is unused — nothing about the code itself. It draws a direct line from event-stream (2018) to ua-parser-js (2021) to this Axios compromise, arguing the pattern keeps repeating because the registry's trust model has not fundamentally changed.

├── "Loose semver ranges and absent lockfiles turn automated dependency resolution into an attack distribution mechanism"
│  └── top10.dev editorial (top10.dev) → read below

The editorial highlights that any project running `npm install` without a lockfile or with a loose semver range like `^1.x` could have pulled the compromised version automatically with no human decision required. The ecosystem's convenience-first dependency resolution effectively did the attacker's distribution work for them, turning every `npm install` during the exposure window into a potential infection vector.

└── "The exposure window between malicious publish and removal is the critical unsolved problem"
  └── top10.dev editorial (top10.dev) → read below

The editorial frames the time between publish and removal as 'the kill zone,' arguing that even when NPM security acts to pull affected versions, the damage is done during the exposure window. The trojan established outbound connections to attacker infrastructure enabling remote command execution on developer machines and CI/CD servers, meaning reactive removal is insufficient as a defense.

What happened

Axios — the HTTP client library downloaded roughly 50 million times per week from NPM — was compromised. Malicious versions were published to the registry containing a remote access trojan (RAT) that could give attackers persistent access to any machine that installed the tainted package. StepSecurity's research team identified the compromise and published a detailed breakdown of the attack chain.

The malicious payload was embedded in what appeared to be routine version updates. Any project running `npm install` without a lockfile, or with a loose semver range like `^1.x`, could have pulled the compromised version automatically — no human decision required. The trojan established outbound connections to attacker-controlled infrastructure, enabling remote command execution on developer machines and CI/CD servers alike.

The NPM security team acted to pull the affected versions, but the window of exposure — the time between publish and removal — is the kill zone. Every `npm install` during that window was a potential infection vector.

The anatomy of a registry trust failure

To understand why this keeps happening, you need to understand what NPM actually verifies at publish time: almost nothing about the code itself. The registry confirms that the publishing token is valid and that the version number hasn't been used before. That's it. There is no code review, no diff analysis against previous versions, no behavioral sandboxing, and no secondary maintainer approval required by default. A single compromised token is sufficient to push arbitrary code to millions of machines.

This is not a novel attack pattern. The event-stream incident in 2018 followed the same playbook: gain publish access, inject payload, wait for the ecosystem's automated dependency resolution to do the distribution work for you. The ua-parser-js compromise in 2021 was nearly identical. The colors/faker sabotage in 2022 demonstrated that even intentional maintainer action could weaponize the same trust chain.

What makes the Axios case particularly concerning is scale and centrality. Axios isn't a niche utility — it's infrastructure. It sits in the dependency tree of frameworks, CLIs, backend services, and frontend applications across the industry. A conservative estimate puts the transitive dependent count in the hundreds of thousands of packages. When you compromise Axios, you're not attacking one project; you're attacking a supply chain node with extraordinary fan-out.

The community reaction on Hacker News (1,674 points) reflected a familiar mix of alarm and fatigue. Several commenters noted that they'd been advocating for stricter publish controls for years. Others pointed out that NPM's two-factor authentication adoption among top package maintainers remains incomplete. The uncomfortable truth is that the JavaScript ecosystem's dependency model — deep trees, automatic resolution, mutable packages — was designed for developer convenience, not supply chain security.

Why the standard advice isn't enough

The immediate response playbook is well-established by now: check your lockfiles, audit your `node_modules`, pin exact versions, run `npm audit`. These are necessary hygiene steps, and if you haven't done them yet, stop reading and go do them now.

But let's be honest about the limitations. Lockfiles protect you from pulling *new* malicious versions — they don't help if the compromised version is already in your lockfile from a legitimate install before the attack. `npm audit` depends on the advisory database being updated, which introduces its own lag. Pinning exact versions means you stop getting security patches automatically, which creates a different class of risk.

The more robust defenses are architectural:

Registry mirroring and proxying. Tools like Artifactory, Verdaccio, or npm Enterprise let you run a local registry that caches packages. When a package is pulled from the public registry, your mirror retains the version you vetted. New publishes don't automatically flow through. This is the single highest-leverage change most organizations can make, and most don't bother because it adds operational overhead.

Provenance verification. NPM introduced package provenance in 2023, which cryptographically links a published package to a specific source commit and build process. If Axios had enforced provenance attestation, the attacker would have needed to compromise the CI/CD pipeline itself — not just a publish token — to inject the malicious payload. But provenance is opt-in, and adoption among even top-1000 packages is partial at best.

Install-time policy enforcement. Tools like Socket.dev and StepSecurity (the researchers who discovered this compromise) analyze packages for suspicious behaviors — network calls, filesystem access patterns, obfuscated code — before they enter your dependency tree. This is the closest thing the ecosystem has to behavioral analysis at install time, and it's where the Axios compromise was actually caught.

Minimal dependency philosophy. The most radical mitigation is also the simplest: use fewer dependencies. Axios wraps the Fetch API, which is now available natively in Node.js 18+ and all modern browsers. For many projects, the correct response to this incident isn't better Axios hygiene — it's dropping the dependency entirely and using `fetch()`. Every dependency you remove is an attack surface you eliminate.

What this means for your stack

If you're a team lead or staff engineer, this is a forcing function for three conversations:

First, audit your critical path dependencies. Not all 1,200 packages in your `node_modules` are equal. Identify the 10-20 that have deep transitive reach or run in privileged contexts (CI, deployment, server-side). Those are your supply chain crown jewels. Know who maintains them, whether they use 2FA, whether they publish with provenance.

Second, implement a registry proxy if you haven't. The operational cost is real but bounded. A Verdaccio instance or Artifactory tier costs less than one compromised production server. Configure it to cache aggressively and require manual approval for new packages or major version bumps on your critical-path list.

Third, revisit your dependency philosophy. The JavaScript ecosystem's cultural default of `npm install` for everything has a compounding security cost. Every transitive dependency is an implicit trust relationship with a maintainer you've never met. For foundational HTTP operations, `fetch()` is now a realistic alternative that removes Axios from your attack surface entirely.

Looking ahead

Three major NPM supply chain attacks in two years, each following the same basic pattern, each met with the same mitigation advice. The ecosystem's tooling has improved — provenance, Socket, Sigstore — but adoption lags because convenience still wins over security in most development workflows. Until the default NPM install path includes behavioral analysis or provenance verification as a non-optional step, we'll keep having this conversation every few months with a different package name in the headline. The vulnerability isn't in Axios. It's in the trust model itself.

Hacker News 1901 pts 780 comments

Axios compromised on NPM – Malicious versions drop remote access trojan

→ read on Hacker News
bob1029 · Hacker News

"Batteries included" ecosystems are the only persistent solution to the package manager problem.If your first party tooling contains all the functionality you typically need, it's possible you can be productive with zero 3rd party dependencies. In practice you will tend to have a few,

h4ch1 · Hacker News

I can't even imagine the scale of the impact with Axios being compromised, nearly every other project uses it for some reason instead of fetch (I never understood why).Also from the report:> Neither malicious version contains a single line of malicious code inside axios itself. Instead, both

postalcoder · Hacker News

PSA: npm/bun/pnpm/uv now all support setting a minimum release age for packages.I also have `ignore-scripts=true` in my ~/.npmrc. Based on the analysis, that alone would have mitigated the vulnerability. bun and pnpm do not execute lifecycle scripts by default.Here's how to

woodruffw · Hacker News

There’s a recurrent pattern with these package compromises: the attacker exfiltrates credentials during an initial phase, then pivots to the next round of packages using those credentials. That’s how we saw them make the Trivy to LiteLLM leap (with a 5 day gap), and it’ll almost certainly be similar

himata4113 · Hacker News

I recommend everyone to use bwrap if you're on linux and alias all package managers / anything that has post build logic with it.I have bwrap configured to override: npm, pip, cargo, mvn, gradle, everything you can think of and I only give it the access it needs, strip anything that is use

// share this

// get daily digest

Top 10 dev stories every morning at 8am UTC. AI-curated. Retro terminal HTML email.