The .js.map file sitting next to your bundle is your original source code
作者:Seaworthy · 2026年8月22日
Photo by Artturi Jalli on Unsplash
Open the network tab on almost any production site and request the JavaScript bundle with .map appended:
GET /static/js/main.a1b2c3d4.js.map
If that returns a JSON file instead of a 404, you've just downloaded the original, unminified source of the application, mapped line by line back from the bundle that actually ships to browsers.
A source map is a translation key for your entire bundle
Minifiers exist to make bundles small and unreadable, which is good for load time and bad for debugging production errors. A source map is the fix for the debugging half: it's a file that maps every line and column in the minified bundle back to the original file, function name, and line number it came from. Browser devtools and error-tracking tools use it to show you a real stack trace instead of at t.n (main.a1b2c3d4.js:1:48213).
That mapping runs in both directions. Anyone with the source map and the bundle can reconstruct the original source, with original variable names, original comments, and original file structure intact. Most build tools generate source maps by default in production builds, because they're genuinely useful for debugging errors that only happen in production. Whether they also get served publicly is a separate decision that a lot of default configurations make for you, silently, in the direction of "yes."
What actually ends up exposed
The original source isn't just cosmetically different from the minified bundle, it's the same code a reviewer would see in your repository, including things that were never meant to leave it:
- API endpoint paths and internal service names that aren't referenced anywhere in your public-facing documentation
- Comments left in by developers, the kind that say
// TODO: remove this hardcoded key before launch - Business logic an attacker can read line by line to find validation gaps, rather than guessing at them from the minified output
- Occasionally, literal credentials or API keys that were meant to be build-time constants and ended up inlined into the bundle, now readable in full instead of buried in minified noise
None of this requires finding a vulnerability first. It's a GET request to a predictable URL pattern that most bundlers use by default.
Turning them off, or gating them properly
The straightforward fix is to not generate production source maps at all, if you don't need them:
// next.config.js
module.exports = {
productionBrowserSourceMaps: false,
}
// webpack.config.js
module.exports = {
devtool: false, // or 'hidden-source-map' if you upload maps to an error tracker
}
If you do want source maps, because your error tracking tool (Sentry, Bugsnag, or similar) needs them to symbolicate stack traces, the right pattern is to generate them, upload them directly to that tool during your build step, and then delete them or exclude them from what actually gets deployed to your CDN or static hosting. hidden-source-map in webpack generates the map file and a reference comment pointing to it, without exposing the reference in the shipped bundle, which stops browsers (and anyone poking around) from finding it via the bundle itself. It's still your job to make sure the .map files themselves never land in the public directory.
# quick check: does your production build serve maps?
curl -s -o /dev/null -w "%{http_code}\n" https://your-app.example.com/static/js/main.js.map
A 200 there means the map is public. A 404 means it isn't.
Why this slips through so often
Source maps are a build-time concern, generated by whatever bundler your framework picked for you, and the default for "generate source maps in production" varies by tool and by framework version. Nobody writes code that says "expose my source," it's an emergent property of a default that was reasonable for local development and never got revisited for the production build. An assistant asked to "set up a Next.js app" or "configure webpack for production" has no reason to flag this, because from the bundler's point of view, generating a source map is the responsible thing to do. Whether it also gets deployed to a public CDN is a separate step the tooling doesn't enforce either way.
Seaworthy checks whether production builds ship publicly accessible .map files alongside their bundles, since the setting that controls it is usually one line and rarely gets a second look once the build works.
本文由 AI 生成,总结了公开可用的来源。
Seaworthy 会扫描你的代码仓库,发现类似本文提到的各种问题。
安全漏洞、泄露的密钥和配置错误——在部署前捕获。免费运行,无需账户。