Skip to content
Blog
Playbook

You shipped your source code to production

You look at your live site, see a wall of minified a.b(c) gibberish, and figure your code is safe. It isn't — if a source map shipped alongside it, a stranger can turn that gibberish back into your original, commented source in one click.

The buckingfugs crewJuly 12, 20264 min read

A source map is a .map file your build tool generates so that, when something breaks in production, your browser's devtools can show you the original code instead of the minified soup. It's genuinely useful — for debugging. The problem is what happens when that same file is left reachable to the public: it's a complete, faithful blueprint for turning your shipped bundle back into the source you wrote.

At the bottom of a minified JavaScript file there's usually a comment like //# sourceMappingURL=main.a1b2c3.js.map. Devtools follows it automatically. So does anyone curious. Fetch that .map and you get your original file names, folder structure, comments, and un-minified logic handed back verbatim.

What actually leaks

“Someone can read my frontend” sounds harmless — it runs in their browser anyway. The damage is in the detail a map restores that minification had stripped:

1

Your file and folder structure

src/lib/auth/adminGuard.ts, src/api/internalBilling.ts — the map keeps original paths, so your whole architecture and every internal endpoint name is laid out like a directory listing.

2

Comments and dead code

The // TODO: remove admin bypass before launch you forgot about is back, in full. So are commented-out experiments, feature-flag names, and internal notes about how the auth check really works.

3

Secrets minification hid by accident

A hardcoded key is easy to miss in a minified blob but obvious in restored source — which is exactly how a key in your bundle goes from “technically present” to trivially findable.

Check it in one request

Open your live site, find a bundled script's URL in the network tab, and ask for its map. From any terminal:

terminal
$curl -s -o /dev/null -w "%{http_code}" https://yourdomain.com/assets/main.a1b2c3.js.map
# 200 = your source map is public. 403 or 404 = good.
$ curl -s https://yourdomain.com/assets/main.a1b2c3.js.map | head -c 300
# See "sources" and "sourcesContent"? That's your codebase, downloadable.

The fix is one build setting

Unlike most findings, this one usually isn't an edge rule or a rotate-everything scramble. In almost every case the maps shouldn't be deployed at all, and turning them off is a single flag.

  1. 1

    Turn off production source maps.

    In Next.js, ensure productionBrowserSourceMaps is not enabled (it's off by default). In Vite, set build.sourcemap: false. In Create React App, build with GENERATE_SOURCEMAP=false. Rebuild and the .map files stop being emitted.
  2. 2

    Or keep them private for error tracking.

    If you rely on maps to de-minify stack traces (Sentry and friends), you don't have to give them up — upload them to your error tracker at build time and delete them from the public deploy. The tracker gets the map; the internet doesn't.
  3. 3

    Block .map at the edge as a backstop.

    Add a rule so *.map is never served — a Cloudflare WAF rule or an nginx location ~ \.map$ { deny all; }. Belt and suspenders, in case a future build re-enables them.

Where it sits on the list

Be honest about severity: an exposed source map is not a live breach the way a leaked secret key is. Nobody drains your account with your folder structure. What it does is hand an attacker a map of the building — every door, every internal name, every note-to-self — which turns “poke at a black box” into “read the plans and go straight for the weak spot.” It's information disclosure, and it makes every other weakness easier to find.

The upside: it's one of the cheapest findings to close. One build flag, one rebuild, and your shipped code goes back to being an opaque blob — which is all a stranger was ever supposed to get.

Not sure whether your build is leaking source maps? We follow the sourceMappingURL on your live scripts and flag any that resolve. Scan in about 20 seconds.

Scan your site free →