Axios Hijacked, Claude Code Leaked, wtf is going on

March 31, 2026 will go down as one of the worst days in npm history. Two separate incidents

  • one a sophisticated state-sponsored attack,
  • the other a packaging blunder by one of the most well-funded AI companies on the planet, exposed a fundamental problem with how the open source ecosystem handles trust.

If you build anything that used npm install, this matters to you, if you use

The Axios Supply Chain Attack

Axios is the HTTP client library that half the internet runs on. With over 100 million weekly downloads, it sits in the dependency tree of countless applications, CI/CD pipelines, and developer machines worldwide.

On March 31st, a North Korean threat group (tracked as UNC1069 by Google, Sapphire Sleet by Microsoft) hijacked the npm account of Axios’s lead maintainer and pushed two poisoned versions: 1.14.1 and 0.30.4. They tagged them latest and legacy respectively — meaning any fresh npm install axios would pull the compromised code automatically.

How the attack worked

The clever part: they didn’t touch a single line of Axios source code. Instead, they added a phantom dependency called plain-crypto-js to the package.json manifest. This package had been pre-staged 18 hours earlier — first as a clean decoy (v4.2.0) to build registry history, then updated with the payload (v4.2.1) just before the Axios versions were pushed.

When npm resolved the dependency tree, plain-crypto-js installed silently and its postinstall hook ran a heavily obfuscated dropper script called setup.js. This script checked the host operating system, then phoned home to a command-and-control server to download a platform-specific Remote Access Trojan:

  • Windows: A fileless PowerShell execution loop, with the interpreter copied to %PROGRAMDATA%\wt.exe
  • macOS: A binary disguised as an Apple cache daemon at /Library/Caches/com.apple.act.mond
  • Linux: A Python script dropped to /tmp/ld.py

After deploying the RAT, the dropper deleted itself and replaced the malicious package.json with a clean stub — covering its own tracks. The goal was credential harvesting: AWS keys, GitHub tokens, SSH keys, database passwords, and anything else stored on developer workstations and build servers.

The malicious versions were live for approximately three hours (00:21 to 03:29 UTC) before being pulled from the registry. In that window, Huntress observed at least 135 endpoints across multiple organisations contacting the attacker’s C2 infrastructure. Given the scale of Axios’s install base, the true blast radius is likely far larger.

What to do if you were exposed

If any system in your environment ran npm install during that window and resolved to axios@1.14.1 or axios@0.30.4:

  • Assume full compromise. This isn’t a “change your password” situation. Isolate the machine.
  • Rotate everything. Every API key, SSH key, npm token, cloud credential, and .env value that was accessible on that system needs to be revoked and reissued.
  • Check for RAT artifacts: com.apple.act.mond on macOS, wt.exe in %PROGRAMDATA% on Windows, ld.py in /tmp on Linux.
  • Audit CI/CD logs. Any pipeline that ran during the window needs to be reviewed. Rotate all injected secrets.
  • Rebuild from known-good state. Don’t try to clean in place.

The Anthropic Source Code Leak

On the same day — in a coincidence that must have made Anthropic’s security team want to crawl under their desks — the company accidentally shipped the entire source code of Claude Code, their flagship AI coding CLI, to the public npm registry.

Version 2.1.88 of @anthropic-ai/claude-code included a 59.8 MB source map file. For non-frontend developers: a source map is a debugging artifact that maps minified production JavaScript back to the original human-readable source. In this case, it exposed approximately 512,000 lines of TypeScript across 1,900 source files.

Within hours, the code was mirrored on GitHub repositories that racked up tens of thousands of stars before Anthropic’s DMCA takedowns started landing. A Python clean-room rewrite appeared the same day. The code is permanently in the wild.

Anthropic confirmed to VentureBeat that it was a packaging error caused by human error — no customer data, credentials, or model weights were involved. But the timing is brutal: this came less than a week after a separate CMS misconfiguration exposed internal documents about an unreleased model. Two significant accidental disclosures in under a week from a company whose tools are used to write and ship code at scale.

The intersection that really matters

Here’s the detail that got less attention than it should have: the Axios supply chain attack and the Claude Code leak overlapped on the npm registry on the same morning. Developers who installed or updated Claude Code via npm during the 00:21–03:29 UTC window on March 31st may have pulled a trojanised Axios along with it. Attackers have also been typosquatting internal package names from the leaked source code to stage dependency confusion attacks against anyone trying to compile the leaked codebase.

How to Protect Yourself

These two incidents represent different failure modes — one is a hostile attack, the other is an own goal — but the defences overlap significantly. Here’s what actually helps:

1. Use npm ci, not npm install

This is the single most impactful change. npm ci reads your lockfile and installs exactly what’s specified. It won’t silently upgrade to a newer (potentially compromised) version. Use it in every CI/CD pipeline and make it your default habit for local development after initial setup.

2. Commit your lockfiles

package-lock.json (or yarn.lock) is not optional. It’s your snapshot of verified dependency versions. Commit it. Review changes to it in PRs. If a lockfile diff shows a new dependency you didn’t add, that’s a red flag.

3. Disable postinstall hooks by default

The entire Axios attack chain depended on npm automatically running a postinstall script. You can disable this globally:

npm config set ignore-scripts true

When a specific package legitimately needs lifecycle scripts (packages with native bindings, for example), you can allowlist it per-project in .npmrc:

; .npmrc
ignore-scripts=true

Or run a one-off install with scripts enabled when you know you need them. This flips the default from “trust everything” to “trust nothing” — which, given the state of the ecosystem, feels appropriate.

4. Pin exact versions

Stop using carets and tildes in package.json. Change "axios": "^1.14.0" to "axios": "1.14.0". The ^ prefix is what allows npm to silently resolve to a newer version that you haven’t reviewed. If you’re shipping production code or delivering builds to clients, there’s no reason to accept floating version ranges.

5. Enforce a cooldown on new releases

Tools like Aikido’s Safe Chain wrap around npm/yarn/pnpm and enforce a configurable minimum package age — 48 hours by default. In the Axios attack, plain-crypto-js@4.2.1 existed for less than 24 hours before being pulled into the compromised Axios versions. A simple age check would have blocked it entirely. This is one of the more elegant defences because it requires zero judgement calls — just time.

6. Audit what you’ve already got

Run this across your projects today:

# Check for the specific Axios compromise
grep -r "plain-crypto-js\|axios.*1\.14\.1\|axios.*0\.30\.4" package-lock.json

# See which dependencies run postinstall hooks
find . -path "*/node_modules/*/package.json" -exec grep -l "postinstall" {} \;

# Check for macOS RAT artifact
ls -la /Library/Caches/com.apple.act.mond 2>/dev/null && echo "FOUND" || echo "Clean"

7. Minimise your npm surface area

This one’s less tactical and more philosophical, but it matters: every npm dependency you pull in is an implicit trust relationship with every person who has publish access to that package and its entire dependency tree. The fewer packages you depend on, the smaller your attack surface. If your stack is primarily PHP, Python, or anything else — and you’re only touching npm for build tooling — keep that footprint as lean as possible.

The Bigger Picture

Both of these incidents point to the same structural problem: npm’s trust model assumes that whoever holds the publish token is legitimate. There’s no mandatory 2FA enforcement for all maintainers, no built-in cooldown period on new versions, and no separation between “maintainer” and “publisher” roles.

The ecosystem is slowly moving toward better primitives — npm’s Trusted Publishing with OIDC ties publishes to CI/CD identity rather than long-lived tokens, and package provenance via Sigstore provides cryptographic proof of where a build came from. But adoption is still low, and the damage from a single compromised credential remains catastrophic.

In the meantime, the practical defences are straightforward: lock your dependencies, pin your versions, disable scripts by default, and treat npm install as a potentially hostile operation — because this week proved that it can be exactly that.


For detailed IOCs and remediation guidance, see the incident reports from Microsoft, Google GTIG, Snyk, Elastic Security Labs, and Huntress.

Leave a Comment

Scroll to Top