Source Maps in Production: Your Code's Hidden Tell-All
Source Maps in Production: Your Code's Hidden Tell-All
Source maps are developer tools that map minified code back to original source. In production, they can expose your entire codebase - including comments, internal API endpoints, and logic you thought was hidden.
What Are Source Maps?
When you build a React, Vue, or Next.js app, your code gets minified:
Your original code:\\\javascript
// TODO: Remove before launch - hardcoded for testing
const API_KEY = "sk-test-123";
const ADMIN_ENDPOINT = "/api/internal/admin";
\\\
\\\javascript
const a="sk-test-123",b="/api/internal/admin";
\\\
Source maps (\.map\ files) contain the mapping between minified and original code. If exposed, anyone can see your original source.
How to Check If You're Exposed
Method 1: Check Network Tab.js.map\ filesApp.tsx\, \utils.js\), source maps are activeTry accessing your JavaScript files with \.map\ appended:
\\\
https://yoursite.com/_next/static/chunks/main.js.map
https://yoursite.com/assets/index.abc123.js.map
\\\
If these return JSON data, your source maps are exposed.
What Gets Exposed
With source maps, attackers can see:
| Exposed Item | Risk |
|---|---|
| Original source code | Reveals business logic and potential vulnerabilities |
| Comments (including TODOs) | Often contain sensitive notes, credentials, or security issues |
| Internal API endpoints | Hidden admin routes, debug endpoints |
| Environment variable usage | Shows what secrets the app expects |
| Third-party integrations | Which services you use and how |
| Code structure | Makes finding vulnerabilities easier |
Real Example
Here's what an exposed source map reveals:
\\\javascript
// Original source visible through source map
// FIXME: Rate limiting disabled for demo - re-enable before launch
// Internal admin panel: /api/__admin (no auth required in dev)
export async function fetchUserData(userId) {
// Using staging API key - swap for prod
const response = await fetch(\\${process.env.API_URL}/users/\${userId}\, {
headers: { 'X-API-Key': process.env.INTERNAL_API_KEY }
});
}
\\\
An attacker now knows:
- Rate limiting might be weak or disabled
- There's an admin panel at \
/api/__admin\ - The app uses \
INTERNAL_API_KEY\for auth - They can look for that key elsewhere
How to Disable Source Maps in Production
Next.js:\\\javascript
// next.config.js
module.exports = {
productionBrowserSourceMaps: false, // This is the default, but verify
}
\\\
\\\javascript
// vite.config.js
export default {
build: {
sourcemap: false, // or 'hidden' to generate but not reference
}
}
\\\
\\\javascript
// webpack.config.js
module.exports = {
devtool: process.env.NODE_ENV === 'production' ? false : 'source-map',
}
\\\
\\\bash
# In your build script
GENERATE_SOURCEMAP=false npm run build
\\\
Server-Side Protection
Even if you don't generate source maps, block access at the server level:
Nginx:\\\nginx
location ~* \\.map$ {
deny all;
return 404;
}
\\\
\\\json
{
"headers": [
{
"source": "/(.*).map",
"headers": [{ "key": "X-Robots-Tag", "value": "noindex" }]
}
]
}
\\\
Block \*.map\ files with a 404 response.
Source Map Security Checklist
sourcemap: false\ in your build config.map\ URLs directly.map\ requests at the server levelWhen Source Maps Are Acceptable
- Internal/staging environments: Where only your team has access
- Error monitoring services: Services like Sentry can use private source maps uploaded directly to them
- Hidden source maps: Generated but not referenced in the JS file (\
sourcemap: 'hidden'\)
Key Takeaway
Source maps are invaluable for debugging but dangerous in production. They transform your "secure" minified code back into readable source, complete with all the comments and structure you thought you were hiding. Check your production site today - you might be surprised what's exposed.
Scan your site for security issues -> Run a security audit