Skip to main content

npm's Worst Day: One Attack, One Leak, Zero Trust

Axios was hijacked to deploy a RAT. Claude Code's source leaked via source maps. Same registry, same day — two failure modes your team needs to understand.

npm's Worst Day: One Attack, One Leak, Zero Trust

Ricardo Argüello

Ricardo Argüello
Ricardo Argüello

CEO & Founder

Software Development 9 min read

On March 31, 2026, someone hijacked the axios maintainer’s npm account and published versions that deployed a remote access trojan to anyone who ran npm install. Axios has ~100 million weekly downloads and sits in ~80% of cloud environments.

Hours later — completely unrelated — a researcher discovered that Anthropic had published Claude Code’s entire source code, 512,000+ lines of TypeScript, because a source map file was left in the npm package.

I don’t usually cover two unrelated incidents in the same post, but these two share something that matters: they’re different kinds of broken, and fixing one wouldn’t have helped with the other.

The axios attack

Around midnight UTC on March 31, Feross Aboukhadijeh from Socket.dev sounded the alarm: axios@1.14.1 had pulled in plain-crypto-js@4.2.1, a package that didn’t exist before that day. Thirty-nine minutes later, axios@0.30.4 followed — the attacker poisoned both the 1.x and 0.x branches to maximize blast radius.

What happened next was surprisingly straightforward. The attacker hijacked the jasonsaayman account — axios’s lead maintainer — changed the email to a Proton Mail address, and published both versions manually via npm CLI. Not through GitHub Actions, not through the project’s normal release pipeline. Straight to the registry. The malicious dependency never showed up in the GitHub repository at all.

plain-crypto-js did one thing: execute a postinstall script that deployed a cross-platform RAT.

PlatformPayloadDisguise
macOSBinary at /Library/Caches/com.apple.act.mondApple system daemon
WindowsPowerShell copy at %PROGRAMDATA%\wt.exeWindows Terminal
LinuxPython script at /tmp/ld.pyTemporary file

The dropper used dual-layer encoding — reversed Base64 plus XOR cipher — to evade static analysis. After execution, it self-destructed: deleted setup.js, replaced the malicious package.json with a clean stub showing version 4.2.0. Post-execution, npm list showed nothing suspicious.

Socket.dev’s automated scanner flagged plain-crypto-js within 6 minutes of publication. npm removed the malicious versions within ~3 hours. But in that window, 3% of affected environments had already executed the payload.

If you installed axios between roughly 00:21 and 03:15 UTC on March 31 and got the affected versions, treat your system as fully compromised. Rotate every credential on that machine.

Claude Code’s 512,000-line leak

Hours later, security researcher Chaofan Shou published a finding that had nothing to do with the axios attack but everything to do with npm.

Anthropic’s Claude Code CLI — version 2.1.88 — shipped with a 57 MB source map file that mapped the minified production bundle back to the original TypeScript source. Anyone who ran npm pack or browsed the package contents could read Anthropic’s entire codebase in plain text.

The scale: ~1,900 files, 512,000+ lines of TypeScript, ~40 built-in tools, ~50 slash commands. The core query engine alone was 46,000 lines. The tool definition system was 29,000 lines.

I spent an hour reading through the leaked code. The architecture itself is well-organized TypeScript — nothing scandalous there. What drew my attention was everything else that came along with it.

All of Claude Code’s system prompts — the full instructions that govern how it behaves — were sitting in a JSON file that npm serves to anyone who asks. The Hacker News thread flagged a regex-based system for detecting negative sentiment and profanity in user prompts, which gets logged. That got people talking about what else the telemetry captures.

Then there were the unreleased features. KAIROS is a persistent, always-running assistant mode that watches, logs, and proactively acts on things it notices — gated behind compile-time flags and absent from public builds. A “Capybara” model family showed up in the code, confirming the codename from the Mythos leak three days earlier. And a /buddy command activates a Tamagotchi-style AI pet with species, rarity tiers, stats, and animations.

The one that generated the most debate was an “undercover mode” that strips AI-identifying information from commits. Some saw it as practical tooling; others called it problematic AI impersonation.

How did it happen? Claude Code uses Bun’s bundler, which generates source maps by default unless you explicitly turn them off. Someone forgot to add *.map to .npmignore or configure the bundler to skip source map generation for production builds. According to CyberSecurity News, this is the second similar source map exposure from Anthropic — a comparable incident occurred in early 2025.

No user data was compromised. No malware was involved. But Anthropic’s complete tool architecture, permission system, authentication flows, and unreleased product roadmap are now public.

What connects these two incidents — and what doesn’t

When I sat down to write about the axios attack, I realized I couldn’t ignore the Claude Code leak happening on the same day. Not because the incidents are related — they’re not. But after 20+ years reviewing software infrastructure — and now doing it at IQ Source for B2B clients across Latin America — I keep finding the same thing: teams prepare for one kind of problem and leave the other wide open.

The axios attack is a credential problem. Long-lived npm token, no MFA enforced, no provenance checks. Socket.dev’s automated scanner caught it in 6 minutes — the tooling exists. The fix lives with the security team.

The Claude Code leak is a pipeline problem. Source maps left in the package, no .npmignore, nobody ever ran npm pack --dry-run. No automated scanner flagged it — an external researcher browsing npm found it by accident. The fix lives with DevOps.

The teams responsible don’t even overlap. Authentication hardening is the security team’s job. Build artifact auditing is DevOps. In most organizations, those teams don’t talk to each other about npm — and npm doesn’t distinguish between the threats either. It’s just a registry, serving packages regardless of whether they were compromised by an attacker or bloated by a forgotten debug file.

AI agents made it worse

Andrej Karpathy posted about his near-miss within hours. He had installed @googleworkspace/cli a few days earlier, which pulled axios 1.13.5 — one version before the poisoned release. If he’d installed it a few hours later, the unpinned dependency would have resolved to the compromised version.

His observation was the one that stuck: “I can’t feel like I’m playing russian roulette with each pip install or npm install (which LLMs also run liberally on my behalf).”

That phrase — “which LLMs also run liberally on my behalf” — deserves its own section. Six days ago, we wrote about how the LiteLLM attack broke AI trust chains at the dependency level. But the LiteLLM post didn’t cover what happens when AI coding agents run npm install on their own. No diff review. Resolve to latest by default. At 3 AM while you sleep.

Multiple replies in Karpathy’s thread named the exact scenario — “agentic flows that auto-install deps without pinning are the worst case. Compromised at machine speed with no one checking the diff.” The risk isn’t just that your dependency chain has weak links. It’s that AI tooling is now accelerating through those weak links faster than any human can review.

What actually prevents this

Dependency pinning alone wouldn’t have prevented either breach. The specific controls that would have actually stopped them are different for each case:

Against the axios attack

pnpm’s default security model. pnpm disables postinstall scripts by default for all packages except explicitly allowlisted ones. If the affected environments had used pnpm instead of npm, the RAT dropper would never have executed — even with the compromised version installed.

SLSA provenance. The malicious versions had no provenance record because they were published manually via CLI, not through the project’s normal GitHub Actions pipeline. If npm enforced provenance checks for popular packages, the unsigned versions would have been rejected at install time.

Minimum release-age constraints. A policy that rejects packages published within the last 72 hours would have given the community time to analyze before anyone installed. socket.dev already offers this in their Socket Firewall.

Against the Claude Code leak

npm pack --dry-run before every publish. One command that shows you exactly what files will be included in the package. If anyone at Anthropic had run this before publishing 2.1.88, the 57 MB source map file would have been immediately visible.

Explicit .npmignore. Add *.map, *.map.js, and any debug artifact to .npmignore. Don’t rely on .gitignore — npm uses .npmignore if it exists and falls back to .gitignore if it doesn’t.

Bundler configuration. Bun generates source maps by default. For production builds, set sourcemap: "none" explicitly. Don’t leave defaults for production artifacts.

CI/CD publish verification. A pre-publish step that checks total package size and flags unexpected files. A 57 MB source map in a CLI tool package should have triggered an alert before it reached the registry.

Anthropic’s fourth incident in six weeks

We use Claude every day at IQ Source and build client solutions with it. That doesn’t change what four incidents in six weeks tells you about operational maturity — and if you’re evaluating AI vendors, this pattern should be on your radar.

In six weeks: Mrinank Sharma resigned citing internal governance concerns. Anthropic dropped its pause commitment from the Responsible Scaling Policy. The Mythos leak exposed ~3,000 internal documents via a CMS misconfiguration. And now Claude Code’s full source code published to npm via a build configuration error.

We covered the vendor trust implications in detail three days ago, and I stand by that analysis. Today just added a fourth data point. If your vendor evaluation framework still focuses on model benchmarks and certifications without looking at the vendor’s operational track record, you’re missing the pattern.

What we changed at IQ Source after this

We ran npm pack --dry-run on every package we maintain before noon on March 31. No source maps, no .env files, no surprises. That took 15 minutes. It should have already been part of our CI — now it is.

Then we audited lockfiles for every active client project. We looked for three things: packages with postinstall scripts we hadn’t reviewed, unpinned caret-range dependencies on high-download packages, and CI pipelines that resolve latest instead of installing from a lockfile.

The first check is about what you consume. The second is about what you ship. If you only do one, March 31 showed what happens with the other.

I keep coming back to something Karpathy wrote in a reply on that thread: “I can’t feel like I’m playing russian roulette with each npm install.” If your team feels the same way — or if you’ve got AI agents doing the installing for you — send us your package-lock.json at contact. We’ll tell you which side of March 31 you’re exposed on.

Frequently Asked Questions

npm security supply chain attack axios Claude Code source maps dependency management build pipeline security

Related Articles

Your Code Review Was Built for Humans. 41% of Code Isn't
Software Development
· 8 min read

Your Code Review Was Built for Humans. 41% of Code Isn't

41% of code shipped in 2025 was AI-generated, with a 1.7x higher defect rate. Your review process assumes the author understands the code. That's over.

code quality code review AI-generated code
What Your AI Won't Ask (and Your Startup Will Pay)
Software Development
· 6 min read

What Your AI Won't Ask (and Your Startup Will Pay)

A founder lost $87,500 because his AI generated working code without questioning security. AI tools answer what you ask, not what's missing.

vibe coding software security startups