Blog / Build & Deploy

My Users Found My Source in Their Browser: Fixing Exposed Source Maps

· Fortus Team · 5 min read

Imagine shipping your app, getting a friendly message from a user, and realizing they are reading your original source code in their browser. Not the minified bundle — the real thing, with component logic, route structure, and comments intact. Here's a scenario I keep seeing: a builder shares the story as a mea culpa, because a community member opened DevTools, found the source maps, and gently pointed out that everything was public. It happens because the development experience hides the difference. Your dev server ships readable code by design, and the production build is supposed to strip that away. But one config flag, one committed map file, or one dev-mode deploy later, and your production bundle carries a map back to the originals. Nobody notices, because the app works exactly the same either way. The only people who notice are the curious ones opening the Sources panel.

What source maps are and why they leak so much

A source map is a file that connects a transformed bundle back to the original source. Browsers use it to show you readable code while debugging. Build tools generate them alongside your JavaScript, often with a comment at the bottom of the bundle pointing at the map file. When those map files are published with your site, anyone can reconstruct your frontend source: page components, API call shapes, hidden feature flags, client-side validation logic, and sometimes comments with internal hints. Unminified production bundles are the same class of problem. If the deployed JavaScript was built in development mode, it is already readable without any map at all. None of this means your backend is exposed. But frontend source still teaches an attacker your route layout, your API endpoints, where your auth checks live client-side, and which ideas you considered worth flagging. It turns black-box probing into white-box reading. That is a meaningful head start you did not intend to give away.

Where the exposure hides in your repo

The good news is that this entire problem is decidable from files. There are only a few places to look, and they differ slightly by stack. In Next.js, the flag is productionBrowserSourceMaps in the config file. It defaults to off, which is what you want, but any explicit true value re-enables public maps. In Vite, look for sourcemap options in the build config. In webpack, look for devtool settings that emit full source maps. Beyond flags, check what actually gets published: committed map files under output directories, map files sitting in public folders, and sourceMappingURL comments at the bottom of shipped JavaScript assets. Also check your deploy configuration and build scripts. A build command that runs in development mode, or a publish directory that includes build intermediates, can ship readable bundles even when the config looks right. Continuous integration steps that build and publish are part of the chain too. The question is always the same: does the thing the browser downloads include a path back to the originals. Handled setups are explicit about this. Maps are disabled for browser production builds, or generated only as hidden maps uploaded to a private error-tracking service that never serves them publicly. Production bundles are minified, and no map files sit in published directories.

A manual self-test you can run in five minutes

Here is a concrete self-test you can run manually on your own app right now. No tools required beyond a browser and a text search. First, open your production site in a browser, open DevTools, and look at the Sources panel. If you see your original folder structure and readable component files for the production URL, maps are public. Second, try fetching a map directly: take a production JavaScript URL and append .map, and see whether it downloads. Third, download one production JavaScript file and search its tail for sourceMappingURL. That comment is the pointer browsers follow. Then go to the repo side. Search your bundler config for the sourcemap flags named above and confirm they are off for production. Search your published output directories for map files. Check your deploy config to confirm which directory actually gets published, and make sure build intermediates are not included. If any step shows maps or readable source, fix the flag, remove the published map files, and redeploy, because edge caches can hold stale maps even after the repo is clean.

Where a file scanner helps

A source-file scanner fits this problem neatly because every signal lives in the repo. It can read your bundler config for the map-enabling flags, list map files under published directories, and flag sourceMappingURL comments or dev-mode build steps before they ship. Think of it as a pre-deploy gate rather than a live probe. The scanner reads your config and output paths and tells you which flag or file would publish source, with the file path and excerpt attached. You still do the browser-side confirmation yourself after deploy, and you still handle the redeploy that clears cached maps at the edge. But the repo-side mistake gets caught at commit time instead of by a curious user months later. If you take one habit from this post, let it be the five-minute browser check after every production deploy. Build the habit, pin the config, keep maps private to your error tracker, and your users will find features in their browser instead of your source.

Automated Code Review

Keep your source code private

Fortus checks your bundler configurations and build outputs for exposed source maps and unminified bundles before they ship to production.

or learn more about Fortus →