Remediation Guides

JavaScript Source Map Detected: How to Disable Source Maps in Production

26 September 2026 8 min read

A “JavaScript Source Map Detected” finding means your web server publicly serves .js.map files that let anyone rebuild your original, unminified front-end source code. Fix it by building production bundles without public source maps, deleting any .map files from the deployed site or blocking them at the web server, then rescanning.

What the scanner is actually detecting

Tenable Web App Scanning reports this as plugin 114132, JavaScript Source Map Detected, in the Web Applications family with severity Info. Acunetix lists the same issue as Javascript Source map detected, also rated Info, classified under CWE-16 and tagged as information disclosure. Both descriptions make the same point: production JavaScript is usually combined and minified, and a source map is a file that maps the transformed code back to the original source.

A browser finds a map in one of two ways:

  • A comment on the last line of the bundle, such as //# sourceMappingURL=main.3f2a1c.js.map
  • A SourceMap HTTP response header on the script (the older X-SourceMap form is deprecated)

Neither plugin page documents the exact probe, so treat the URL in the finding’s evidence as your test case and work outward from there.

How serious is an exposed source map?

Both vendors rate it informational, and that is fair. Client-side JavaScript is already public, because the browser has to download it. What a source map adds is readability: the original file tree, variable and function names, developer comments and, when the map includes sourcesContent, the full original source of every module.

That speeds up reconnaissance. An attacker reading clean source can quickly find API routes the UI never links to, admin-only screens, feature flags, client-side validation logic, internal hostnames left in comments and the names of bundled npm packages. It does not expose server-side code, and it does not create a vulnerability by itself.

One honest caveat: if the readable source reveals an API key or token, the map did not leak it. The minified bundle already contained it. Rotate the secret and move it out of client code; removing the map alone does not fix that.

How to confirm it on the host

Start from outside, the way the scanner sees the site. Replace the bundle name with one from the finding:

# List the script bundles the page loads
curl -s https://app.example.com/ | grep -oE '<script[^>]+src="[^"]+"'

# Look for a map reference at the end of a bundle
curl -s https://app.example.com/static/js/main.3f2a1c.js | tail -c 300

# Check for a SourceMap response header
curl -sI https://app.example.com/static/js/main.3f2a1c.js | grep -iE '^(x-)?sourcemap'

# Request the map itself and inspect the first bytes
curl -s -o /dev/null -w '%{http_code} %{content_type}n' https://app.example.com/static/js/main.3f2a1c.js.map
curl -s https://app.example.com/static/js/main.3f2a1c.js.map | head -c 120

A real map is JSON that starts with {"version":3 and contains sources and mappings keys. Request the .map URL even when the bundle has no comment: maps built in “hidden” mode carry no reference but may still sit next to the bundle. Watch for single-page app fallbacks, which answer every unknown path with index.html and a 200 status; a text/html response is not a map.

Then check the deployed files directly. On Linux:

find /var/www/app -type f -name '*.map'
grep -rl --include='*.js' 'sourceMappingURL=' /var/www/app

On a Windows IIS server:

Get-ChildItem -Path C:inetpubwwwroot -Recurse -Filter *.map
Get-ChildItem -Path C:inetpubwwwroot -Recurse -Filter *.js | Select-String -Pattern 'sourceMappingURL=' -List | Select-Object Path

How to fix it

Fix it in two layers: stop the build from publishing maps (the root cause), then block .map requests at the web server as a safety net for old files and future mistakes.

Step 1: stop generating public source maps

Toolchain Setting for production Effect
Create React App GENERATE_SOURCEMAP=false No maps are generated for the production build
Angular CLI "sourceMap": false in the production configuration No maps in the build output
webpack devtool: false No source map is emitted
Vite build.sourcemap: false (the default) No maps; check nobody set it to true
Next.js Remove productionBrowserSourceMaps: true Browser maps are off in production builds by default

Create React App. Put the variable in .env.production at the project root, which npm run build reads (no REACT_APP_ prefix is needed for this setting):

GENERATE_SOURCEMAP=false

Angular. In angular.json, under projects > your-app > architect > build > configurations:

"production": {
  "sourceMap": false
}

CLI-generated workspaces typically set "sourceMap": true in the development configuration, so also confirm your pipeline actually builds with the production configuration.

webpack. In the production config:

module.exports = {
  mode: 'production',
  devtool: false,
};

Vite. In vite.config.js:

import { defineConfig } from 'vite';

export default defineConfig({
  build: {
    sourcemap: false,
  },
});

Keeping readable stack traces without publishing maps

If your error tracker needs maps, generate them without the public reference and never deploy them. Use webpack devtool: 'hidden-source-map', Vite build.sourcemap: 'hidden', or Angular’s object form, "sourceMap": { "scripts": true, "hidden": true }. All three still write .map files to the output folder. Webpack’s own documentation warns not to deploy hidden maps to the web server, so upload them to your error tracker in CI, then remove them before the deploy step:

find dist -type f -name '*.map' -delete

For static sites in S3, exclude maps from the upload and remove any already there (then invalidate the CDN cache):

aws s3 sync dist/ s3://my-bucket/ --exclude "*.map"
aws s3 rm s3://my-bucket/ --recursive --exclude "*" --include "*.map"

Also clean old releases. Many deploy scripts copy new hashed files but never delete previous ones, so last month’s main.9b1e.js.map may still be served.

Step 2: block .map files at the web server

nginx, inside the server block:

location ~* .map$ {
    return 404;
}

To keep maps reachable from an internal range instead, replace return 404; with allow 10.0.0.0/8; and deny all;. nginx uses the first regex location that matches, in file order, so place this block above other regex locations, and note that a prefix location with the ^~ modifier skips regex checks entirely. Test and reload:

sudo nginx -t && sudo systemctl reload nginx

Apache HTTP Server, in the virtual host or .htaccess:

<FilesMatch ".map$">
    Require all denied
</FilesMatch>

Use Require ip 10.0.0.0/8 instead to allow an internal range. Then run apachectl configtest and reload the service.

IIS, using request filtering in web.config:

<configuration>
  <system.webServer>
    <security>
      <requestFiltering>
        <fileExtensions>
          <add fileExtension=".map" allowed="false" />
        </fileExtensions>
      </requestFiltering>
    </security>
  </system.webServer>
</configuration>

Or from an elevated prompt:

%windir%system32inetsrvappcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /+"fileExtensions.[fileExtension='.map',allowed='False']"

IIS then returns 404 and logs substatus 404.7 (File Extension Denied). If a CDN or reverse proxy sits in front, apply the rule there too, or at least purge its cache.

How to verify the fix and rescan

Repeat the external curl checks. The .map URL should now return 404 or 403 (not an HTML fallback with 200), the bundle should end without a sourceMappingURL comment unless you deliberately kept hidden maps internal, and no SourceMap header should appear. Run the find or Get-ChildItem check on every web node behind the load balancer, not just one.

Then rescan the application in Tenable WAS or rerun the Acunetix scan against the same target. Source map exposure is a runtime observation that only a dynamic scan makes (see what SAST, DAST and SCA scanners can each detect), so a merged pull request does not close the finding; the rescan does.

What can break and how to roll back

  • Error monitoring: trackers that fetched maps from the public URL will show minified stack traces until you upload maps privately.
  • Production debugging: developers lose original source in browser DevTools on the live site. Use the internal-only server rule if they need it.
  • Pipeline scripts: steps that copy or upload *.map files may fail once no maps exist.
  • Unrelated .map files: a server-wide extension block also blocks CSS maps and any other file using the extension. Check with find first.

On the plus side, the Create React App documentation notes that disabling maps avoids out-of-memory failures on smaller build machines. Rollback is simple: revert the build setting and redeploy, or remove the server rule and reload. Keep the maps from each build as private CI artifacts so you can still decode stack traces from that release.

Common false positive reasons

  • SPA fallback responses: if the evidence shows an HTML page returned for the .map URL, nothing was exposed. Attach your curl output showing the content type and first bytes.
  • Dangling references: a bundle may still contain a sourceMappingURL comment while the map returns 404 externally. The exposure is gone, but remove the comment to stop repeat flags.
  • Stale results: a CDN served a cached map, or an old hashed file from a previous release was still on disk.
  • Vendor library maps: a copied library shipping its own .map reveals only public open-source code. Lower risk, but the file is served, so the finding is accurate.
  • nosources-source-map: not a false positive. Per webpack, it still exposes file names and project structure.

FAQ

Is an exposed JavaScript source map a vulnerability?

Not on its own. Tenable and Acunetix both rate it Info. It is an information disclosure issue that makes other weaknesses in your front end easier to find.

Can I keep source maps for error monitoring?

Yes. Build hidden maps, upload them privately to your error tracker during CI, and delete them from the output before deployment.

Does hidden-source-map fix the finding by itself?

No. It only removes the reference comment. If the .map files are still deployed, anyone can find them by appending .map to the bundle URL.

Should CSS source maps be removed too?

The finding covers JavaScript, but .css.map files come from the same build settings. Remove them in the same change.

Tracking this finding across many hosts

Source map findings usually appear on every application built from the same pipeline, so one fix often has to be confirmed on many sites. SITEY, a self-hosted vulnerability management platform, imports findings from 16 scanners and merges duplicates within each scanner but not across scanners, so a Tenable WAS record and an Acunetix record for the same site stay separate. For Acunetix findings it can run a per-finding retest to confirm the map is gone before the item is closed.

Sources

SITEY closes the loop, not just the report.Discover, validate, fix and verify in your own infrastructure.

See pricing