Every few months a team I respect ships something they didn't mean to ship. Not an exploit, not a stolen credential — a package. A perfectly normal npm publish, or a container layer, or a release tarball, that happens to carry a few hundred thousand lines of internal source along with it. Sometimes it's a source map that maps minified output right back to the original tree. Sometimes it's a .git directory that rode along in the build context. Sometimes it's an entire private module that got hoisted into the public artifact because someone changed a glob in a packaging config and nobody read the diff.
The instinct is to treat this as a freak accident. I want to argue the opposite. A source-map leak is not an accident. It's a confession. It's your build pipeline telling you, in public, exactly which controls you skipped on the way to shipping fast. And in the AI era, where code is generated, refactored, and packaged at a speed no human review cadence can match, these confessions are going to get louder.
The real mechanic: you publish your build context, not your intent
Here's the thing people miss. When you cut a release, you are not publishing the thing you meant to publish. You are publishing whatever was sitting in the build context at the moment the package command ran, minus whatever your ignore rules happened to catch. That's it. The contents of a public artifact are defined by subtraction — by what your .npmignore, .dockerignore, files allow-list, or packaging glob excluded — not by what you consciously chose to include.
Subtraction is a terrible default for security. It means the absence of a rule becomes an inclusion. A developer adds a debugging dependency, a CI step bakes in a config file with a token, a bundler flips sourcemap: true for one investigation and nobody flips it back, and suddenly your internals are on a CDN that caches forever. The mistake is small. The blast radius is your entire codebase, your comments, your variable names, your TODOs that say "hack — fix before audit," and occasionally a hardcoded secret that someone swore was rotated.
This is why I tell teams to invert the model. Stop asking "did we remember to exclude the sensitive stuff?" Start asking "can we prove what's actually inside this artifact, and does it match an allow-list we wrote on purpose?" The first question is a hope. The second is a control.
Why AI makes this sharper, not safer
I run security and DevOps for a company that sits behind 1,500+ financial institutions, so I watch supply-chain risk the way a pilot watches weather. The pattern I care about most right now is velocity outrunning hygiene, and AI is the accelerant.
When an assistant scaffolds a service, it produces packaging config, Dockerfiles, and CI workflows that look idiomatic and are mostly correct — which is exactly the problem. They're correct enough that nobody reads them closely. The AI cheerfully enables source maps for better stack traces, copies the whole working directory into the image because that's the common example it learned from, and pins a build step that embeds environment values. None of that is malicious. It's the statistical average of public repos, and the public-repo average leaks. You've automated the median engineer's packaging mistakes and removed the friction that used to make someone pause.
The second AI wrinkle is that leaked internals are now fuel. A few hundred thousand lines of unminified source, complete with auth flows and inline reasoning, is a phenomenal prompt for an attacker running their own model to map your logic, find the validation gaps, and generate targeted probes. We used to comfort ourselves that minification and obfuscation bought time. Against a model that reconstructs intent from structure, that comfort is mostly gone. Treat any leaked source as fully readable by a capable adversary on day one, because it is.
The checklist I actually use
I'm not big on checklists for their own sake, but artifact hygiene is one place where a short, enforced list beats judgment, because the failures are boring and repetitive. Here's the spine of it.
- Diff the artifact, not the repo. Your CI should unpack the exact thing you're about to publish —
npm pack,docker save, the release zip — and assert its contents against an allow-list. If a file appears that isn't on the list, the build fails. This single gate catches the source map, the stray.env, and the accidental private module before any of them reach a registry. - Scan for secrets at the artifact boundary, not just on commit. Pre-commit hooks are good and developers bypass them. The publish step is the last honest checkpoint, and it sees what's really going out. Run secret detection on the packed artifact, and treat a hit as a hard stop plus a rotation event — finding a secret is not the same as it being safe.
- Make source maps a deliberate, separate decision. Production bundles should not carry maps by default. If you need them for error tracking, upload them to your observability tool privately and strip the
sourceMappingURLreference from the public bundle. The map should never be sitting next to the code it explains on a public origin. - Demand provenance, and verify it. Sign your artifacts and generate attestations — SLSA-style provenance and an SBOM — so you can answer "what's in this, and what built it?" with evidence instead of memory. Provenance is only worth the bytes if something downstream actually checks the signature, so wire the verification into your deploy gate.
- Treat the registry as production. A publish is a deploy to the most hostile environment you operate in: the public internet, with caching, mirroring, and no undo. It deserves the same change controls, the same approvals, and the same blast-radius thinking as a prod push, because it is one.
The takeaway
None of this is exotic. The hard part isn't the tooling — npm pack and a content assertion is an afternoon of work. The hard part is admitting that your release process has been running on hope, and that the gap between what you intend to ship and what you actually ship has been quietly widening as you got faster.
So here's the challenge. Pick your most important public artifact and run the unpack-and-diff against it right now, before you read the next thing. Look at every file with fresh eyes and ask whether you meant to send each one to the open internet. If you can't say yes to all of them with confidence, you've just found the most valuable item on your roadmap — and you found it before someone with a model and bad intentions found it for you. The leak is always a confession. The only question is whether you're the one reading it first.
