On March 31, 2026, Anthropic shipped the complete source code of Claude Code to every npm mirror on the planet. Not through a breach. Not through a compromised pipeline. Through a missing .npmignore file.
Version 2.1.88 of @anthropic-ai/claude-code included a 59.8 MB source map containing 512,000 lines of unobfuscated TypeScript across ~1,900 files. The full agent architecture, 44 unreleased feature flags, internal model codenames, system prompts, and safety guardrails were now public. Within hours the code was forked over 41,500 times. A clean-room rewrite hit 50,000 GitHub stars in two hours.
Anthropic’s head of Claude Code, Boris Cherny, called it “plain developer error.” He’s right. And that’s exactly why it matters.
How it happened
Claude Code is built on Bun, the JavaScript runtime Anthropic acquired in December 2025. Bun generates source maps by default during builds. Source maps are JSON files that map minified production code back to the original source, line by line. They’re meant for internal debugging.
The problem: Anthropic’s release pipeline had no .npmignore file and no "files" whitelist in package.json. When you run npm publish without either of those, npm ships everything in the project directory. Build artifacts, source maps, environment files, test fixtures, internal docs. All of it.
So when a developer ran the publish command, a single 59.8 MB .map file went along for the ride. That file contained every line of proprietary source code, fully readable.
Security researcher Chaofan Shou, an intern at Solayer Labs, spotted it around 4:23 AM ET and posted on X. By afternoon, Anthropic confirmed the incident. By then, the internet had already dissected the entire codebase.
What was exposed
This wasn’t a leak of API keys or customer data. It was worse from a competitive and security standpoint:
The source revealed Claude Code’s complete tool orchestration and permission model, 44 feature flags gating over 20 unshipped capabilities (giving competitors a full product roadmap), internal model codenames for unreleased versions, and the full system prompt templates including safety mechanisms and permission escalation flows.
For attackers, the code is a recipe book. With the tool execution logic exposed, anyone can now design malicious repositories that manipulate Claude Code into running background commands or exfiltrating data.
This is not an Anthropic-only problem
Here’s why we’re writing about this: we see the same packaging mistakes across our client base. If your organization publishes packages to npm, PyPI, RubyGems, Maven Central, Docker Hub, or any public registry, you may be leaking source code, credentials, or internal configuration right now without knowing it.
The default behavior of most package managers is to include everything unless told otherwise. That’s a dangerous default.
How to check if your npm packages are leaking
At Profero, our External Attack Surface team runs these checks against client organizations. Here’s how you can do it yourself.
Step 1: Find your packages
# List all packages under your npm scope
curl -s "https://registry.npmjs.org/-/v1/search?text=scope:your-org&size=250" \
| jq '.objects[].package.name'
# Cross-reference with GitHub CI configs
gh search code "npm publish" --owner=your-org
Step 2: Inspect what you’re actually shipping
# Download a package without installing it (safe, no scripts run)
npm pack @your-org/package-name
# List every file in the tarball
tar -tzf your-org-package-name-*.tgz
Step 3: Look for red flags
Report immediately if you find:
| File pattern | Risk |
|---|---|
*.map (source maps) | Full original source code |
.env, .env.* | API keys, database credentials |
.pem, .key, .p12, .pfx | TLS certificates, private keys |
credentials.json, service-account.json | Cloud provider credentials |
.npmrc with auth tokens | Registry auth tokens |
id_rsa, id_ed25519 | SSH private keys |
.git/ directory | Full git history including deleted secrets |
Flag for review:
| File pattern | Risk |
|---|---|
/src/ with TypeScript source | IP exposure |
/test/, /__tests__/ | Hardcoded test credentials, internal URLs |
tsconfig.json, webpack.config.js | Architecture disclosure |
| Sudden package size spike between versions | Accidental build artifact inclusion |
Step 4: Extract and read source maps
If you find .map files, they likely contain your entire codebase. Here’s how to reconstruct the original source:
# Check how many original source files are embedded
cat package/dist/index.js.map | jq '.sourcesContent | length'
# Reconstruct every file
python3 -c "
import json, os, sys
with open(sys.argv[1]) as f:
sm = json.load(f)
for src, content in zip(sm.get('sources',[]), sm.get('sourcesContent',[])):
if content:
path = f'reconstructed/{src}'
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, 'w') as f:
f.write(content)
print(f' Extracted: {src}')
" package/dist/index.js.map
Step 5: Check your version history
Secrets may have shipped in an older version and been removed later. The old version is still on the registry:
# List all published versions
npm view @your-org/package-name versions --json
# Download and compare specific versions
npm pack @your-org/package-name@1.2.3
npm pack @your-org/package-name@1.2.4
diff <(tar -tzf *1.2.3.tgz | sort) <(tar -tzf *1.2.4.tgz | sort)
If the "files" field was added recently, everything before that version was probably exposed.
Five things to fix this week
1. Switch from blacklist to whitelist. Replace .npmignore with a strict "files" array in package.json. Only list the distribution files your consumers need. New build artifacts are excluded by default.
2. Turn off source maps in production builds. Configure Bun, Webpack, esbuild, or whatever you use to skip .map generation for release artifacts. If you need source maps for error monitoring, upload them to Sentry or Datadog privately.
3. Add npm pack --dry-run to your CI pipeline. This lists exactly which files will ship. Fail the build if unexpected files appear. It takes five minutes to set up and would have prevented the Claude Code leak entirely.
4. Set a package size gate. If your package suddenly grows from 2 MB to 60 MB, something is wrong. Tools like size-limit or bundlewatch catch this automatically.
5. Require two-person approval for publishes. No single developer should be able to push to a public registry alone. Use npm’s organization-level permissions and require a CI approval step before the publish command runs.
These controls apply to every registry: npm, PyPI, RubyGems, Maven Central, Docker Hub. Review .dockerignore, MANIFEST.in, and equivalent exclusion mechanisms across all your publishing pipelines.
The bigger lesson
Anthropic is a $60B+ company with some of the best engineers in AI. They still shipped their entire source code because of one missing config file after a build system migration. If it can happen to them, it can happen to you.
The fix isn’t more process. Boris Cherny said it himself: “find ways to go faster, rather than introducing more process.” Automate the checks. Make the CI pipeline refuse to publish a package that contains files it shouldn’t. Make the safe path the easy path.
If you’d like Profero to audit your organization’s external attack surface, including public package registry exposure, contact us.
The Profero Incident Response team has responded to hundreds of cyber incidents worldwide since 2020. Our Rapid-IR platform combines cloud-based technologies, threat intelligence, and field experience to help organizations prevent, detect, and respond to the most advanced threats.
