How do I stop exposing source maps in production?
A .map file published next to your JavaScript lets anyone rebuild the original source behind that bundle. Browsers fetch the map automatically when a script ends with a sourceMappingURL comment, so exposure does not require a determined attacker, only a visitor who opens DevTools. The good news is that most modern build tools leave production source maps off by default, which means the fix is usually to keep the default and delete any stray artifacts.
Why this matters
A source map records how the generated, minified code maps back to the original files you wrote. MDN describes the mechanism plainly: the map links transformed code to its original source, and the browser discovers it through a sourceMappingURL comment appended to the file, which is why a map is useful to a developer and equally useful to anyone else. Chrome DevTools uses the same maps to let you debug the original code rather than the bundle.
What travels in a typical map is more than line numbers. It can include the original module names and directory structure, the original source of each module, comments, and pre-minification identifiers. Unless a build is configured to omit sources, the readable code that made the bundle is right there for the taking. An exposed map is therefore a source-disclosure issue, and it frequently pairs with other leaks such as a version-revealing server header.
How to fix it
The correct default is to publish no source maps. Next.js disables browser source maps during production builds to prevent leaking your source on the client, unless you specifically opt in with productionBrowserSourceMaps; that flag should stay off in production, and when it is on, the maps are written next to the JavaScript files. In webpack the devtool option defaults to false, so set devtool: false explicitly if a shared config turns maps on. Vite has the same shape: build.sourcemap defaults to false, so leave it false for production builds.
// next.config.js — leave source maps off in production
module.exports = {
productionBrowserSourceMaps: false,
}
// webpack.config.js — no published maps
module.exports = {
mode: 'production',
devtool: false,
}
// vite.config.js — default is false; keep it that way
export default {
build: {
sourcemap: false,
},
}
If a third-party error reporter genuinely needs maps to symbolize stack traces, do not publish them. Generate them as hidden maps, which suppress the sourceMappingURL comment and therefore keep the browser from discovering them, upload those files only to the error service, and block request *.map paths at the CDN as a backstop. Putting maps behind authentication sounds safer but is fragile: a single cache rule or shared signed URL can expose them, and it is far easier to stop shipping the file than to prove it is never reachable.
How to verify the fix
Look for the discovery comment on a real bundle, then request whatever filename it names. A published map answers with a 200 and a JSON body; a correctly hardened deployment answers with a 403 or 404.
curl -s https://example.com/static/js/main.abc123.js | tail -c 200 | grep -o 'sourceMappingURL=[^ ]*'
curl -sI https://example.com/static/js/main.abc123.js.map | head -n 1
Automated check
The Auditor does not currently scan for published source maps, so the manual check above is authoritative for this issue. Run it against your largest bundles and any vendor chunk, since a single generated file with a visible map is enough to disclose the rest of your source.
Scan your app free →