All notes

Source Maps Need a Publication Policy

Separate public browser code, private debugging maps and the credentials used to upload them.

English edition, edited for length. Read the complete Chinese original.

The compressed JavaScript can be difficult to read, but a single .map file might contain the complete original source code. Source maps themselves are not inherently dangerous, and client-side logic should not contain secrets; the problem lies in the team mistakenly believing that compression can hide the implementation, and then releasing internal comments, paths, or credentials along with it.

This document only discusses the code sent to the browser. Access control for server-side source maps, as well as runtime stack handling, also need to be reviewed. However, do not mix client-side and server-side debugging assets in a single public directory.

First, Categorize Information, Then Determine the Mapping and Publishing Strategy

Assume that a client-side search module for an open-source blog has no secrets, and the source code is publicly available in a public repository. Public mapping can help the community submit accurate bug reports, which is different from a commercial frontend that includes internal product comments. The strategy should start with content classification: Is the source code originally public? Do the paths contain personal information? Do the comments include unpublished plans? Does the build process include server-side modules? Disabling mapping may reduce the exposure of some information, but it will not change the fact that the client-side logic itself can be observed.

Another scenario is the use of closed-source management applications. While the source code is not publicly available, it does not necessarily mean that browser logic can be kept secret, especially since permission checks and business restrictions still need to be executed on the server-side. Mapping policies can protect unnecessary comments and internal directories, but they cannot be used for authorization control. Reviewers should ask two separate questions: “Is it allowed to publish these debugging assets?” and “Does the client contain any secrets that should not be present?” Both questions must be answered affirmatively before publishing.

The configuration name itself can also be misleading. Source maps can be standalone files, embedded data, or hidden links, and different options affect how they are downloaded and discovered, and do not directly equate to access permissions. Scanning should cover the end of the script, the SourceMap header in the response, and embedded data. If deployment tools automatically upload the entire output directory, standalone files generated by the hidden link mode will still be publicly accessible.

{
  "version": 3,
  "sources": ["../src/search.ts"],
  "sourcesContent": ["/* original source */"],
  "mappings": "..."
}

sourcesContent can be directly included in source code, sources may reveal the local path structure. Whether a map is used, whether the main content is embedded, and whether it is declared in JavaScript (sourceMappingURL) are all determined by the build tool and configuration. It is important to check the final output, rather than just looking at the configuration item names.

Having a missing link does not necessarily mean a file is inaccessible. If .map is still deployed in a public asset directory, others can still guess the path and access it. To restrict access, you should either exclude the asset from public distribution or use a protected storage location, rather than simply deleting a comment.

Debugging can use private mappings

The error monitoring service can receive a map that matches the deployed version, and then map the compressed stack to the source file. Credentials are only stored in the CI (Continuous Integration) system and are not accessible to the client. The version identifier must be reliable, as otherwise, mixing maps from different deployments can lead to incorrect line numbers, which can mislead debugging efforts.

“Hidden source map” typically refers to maps that are generated but not linked within the code. The specific behavior of the tool should be checked in the documentation. It is not a mechanism for access control; instead, a publishing pipeline is needed to send these files to a private target and remove them from the site assets. The preview environment should also follow the same guidelines.

An erroneous event includes the compressed file address, row and column position, and deployment version. The monitoring service uses the corresponding mapping to restore the information. If the file and the mapping do not correspond to the same build, the row number may refer to a completely unrelated function. By associating the file name and deployment identifier using content hashing, and uploading the mapping before or during the deployment phase, we can avoid using “latest version” as a replacement for a clear identifier, as old tags may still send historical errors.

Failure during upload should be handled according to policy: Critical applications may prevent publishing, while standard sites can log downgraded debugging capabilities and continue, but cannot claim that private mappings are ready. Retry uploading using the same artifact, without rebuilding a potentially different mapping. Limit upload credentials to the relevant project, preventing clients from monitoring configurations with management tokens. The browser needs to send events, but does not require mapping management permissions.

Access and retention of the monitoring platform also fall within the scope of release. When private mappings are handed over to a third party, the third party must have access to the source code, and the vendor’s permissions, geographical restrictions, and retention rules must comply with project requirements. Before deleting older versions, consider whether any active clients still exist. Deleting too early can make it impossible to track down historical errors. Unlimited retention increases costs and the amount of data stored. Keeping track of versions is more maintainable than temporarily uploading a batch of files.

Even without a map, secrets can’t be hidden.

Packers typically only change the presentation, not the underlying logic that the browser must execute. API addresses, public tokens, and business conditions can still be observed through the web panel and runtime checks. True secrets must be stored on the server, and sensitive authorization must be verified by the server.

Conversely, publishing a map can be perfectly reasonable for open-source sites: it helps the community debug, and the source code is already publicly available. The decision should be based on information classification and debugging needs, not as a blanket security measure.

Product scanning should cover unexpected paths

Inspect the .map file in the dist directory, JavaScript URL links at the end, embedded data URLs, licenses, and comments. Set up sentinel tests for known fake secrets to ensure they don’t make their way into client code or mappings. The test environment should not use real credentials as search values.

Check if the map contains development paths, personal usernames, internal hostnames, or descriptions of functionalities that should not be publicly disclosed. Even if these are not authentication secrets, they may still violate the organization’s information disclosure policy. The fix should focus on modifying the build input, rather than manually deleting a file after deployment.

After deciding to switch from public mapping to private mapping, the new build exclusion rules only affect newly created products. Existing CDN objects and older versions may still be accessible. To determine the platform’s ability to retain and remove versions, identify and remove any publicly accessible files that need to be removed. However, downloaded source code cannot be recovered. If the old mapping includes credentials, these credentials must be revoked, rather than simply deleting the files. There are two distinct recovery paths: information disclosure and credential revocation.

When the original path contains a developer username or internal hostname, the path should be normalized from the build source, or the mapping content policy should be adjusted. Manually deleting sourcesContent may disrupt debugging and integrity, and repeated deployments will revert to the old behavior. Write the rules into the build and scan, so that the same input produces the same compliant output. Also, check the public license files, comments, and error stacks, and don’t focus all attention on files with the extension “map”.

When using different storage strategies for server mappings, it’s important not to expose source code publicly simply because client files are publicly accessible. Edge applications should package server and client outputs in adjacent directories, and deployment scripts must explicitly identify and expose assets, rather than recursively uploading the entire build root directory. Private drafts, debugging archives, and environment files should be kept outside this boundary.

Reviewing the Debugging Assets Released in a Single Deployment

The release list can be divided into browser scripts, public mappings, private mappings, and server debugging files, with details on their destination and version. If a file appears in both the private upload list and the public assets list, the inspector should report a conflict. The directory name “private” cannot replace deployment rules; only the actual upload scope and access control determine whether a file is public. This list is particularly valuable when a new adapter introduces changes to the directory structure.

After uploading a private file, the monitoring platform should be able to use it, and the public directory should not contain it. Deleting public files should be done using a clear list to avoid accidentally deleting all mapping data and disrupting the server. The build process should first generate complete debugging assets, and then categorize them in the release step to preserve audit evidence. Generating mappings directly can be simpler, but it requires accepting the cost of reduced error information for production.

Client-side errors may contain dynamic script addresses. Scripts from third-party vendors are not created by this site. Do not attribute unrecoverable errors to missing mappings on this site; first identify the source and execution location. The visibility of errors from scripts originating from different sources is also affected by browser rules, and requires specific configuration based on vendor support. Configuring shared error information does not imply obtaining their source code license. Your own source code, vendor source code, and user input should be managed separately.

If the mapping is intentionally exposed, it’s still necessary to check that the source comments don’t contain misleading information. Debug output may include parts of unused source files, so the review scope is not limited to the actual functions executed on the page. Functions that no longer exist may also be exposed through sourcesContent, depending on how the mapping was generated. Instead of inferring the mapping content based on runtime functionality, scan the final file.

The policy should ideally be supported by executable assertions. For example, it should specify that public artifacts should not contain personal paths or fake secrets, that the number of private mappings should match the script list, and that each deployment should have identifiable exception samples. This would allow policy changes to be seen as real differences, without requiring reviewers to individually download and examine compressed files. Finally, it should retain the reason for exceptions. Openly publishing mappings of source code is not an error; the error is unintentionally releasing information that does not belong to the policy.

Using an Old Tab Page Error to Verify Version Association

When a user opens page A during deployment, the site then publishes page B. The search script in the old tab still originates from page A. When it errors, the monitoring event must include the corresponding file and version of page A, and cannot be derived solely from the current domain name for page B. By fixing the version context during client script initialization, it is more reliable than requesting “the latest version” each time. The association between uploading mappings and collecting errors should be based on the actual bytes executed, rather than the time the event arrives.

Keep the “A” page and script, then deploy “B”. Trigger a synthetic anomaly by invoking the controlled function in “A”. The monitoring system should revert “A” to its known source location, while also reverting “B” to its corresponding sample. This cross-experiment can reveal errors in monitoring projects, version strings, or path prefixes. Do not simply declare that historical errors can be identified after a single verification in the latest version. The preservation policy is specifically designed to maintain functionality for older clients that are still active.

Files with the same name may represent different bytes in different environments, especially when content hashing is not used. Mapping records should include the environment and the accurate file identity to prevent preview versions from overwriting production mappings. Retrying uploads using the same artifact will not allow the recreation of a file that may be affected by remote input changes. If the monitoring platform uses its own version naming rules, design and verify the association according to its documentation, and do not assume that a Git SHA automatically satisfies all matching conditions.

Downloadable Mapping and Debugging Service Credentials

Reporting browser errors requires public access configuration, but uploading private mappings requires controlled permissions. If both are represented by the same variable, it could grant the client management capabilities. The deployment script explicitly obtains upload credentials, while the frontend only receives necessary event access information. The event endpoint also needs to be protected and data minimized. The public access identifier is not necessarily an authentication secret, but its purpose and limitations should still be explained.

When CI uploads a mapping, it may print command parameters, failure responses, or the entire environment. Using a supported controlled injection method, and checking the logs to ensure no real tokens are present. The file list can publicly display the quantity and version, without needing to disclose private source paths and content. Testing can be triggered with fake credentials to cause failures, and observe whether the error handling layer outputs the request headers exactly as they are, to avoid leaking sensitive information in a cautious and general CLI debugging mode.

The access permissions for personnel using the monitoring platform must also be maintained. Private maps may contain proprietary source code, and access to error events should be restricted based on the platform’s capabilities. Access to the platform should be revoked when personnel leave, and separate retention periods should be defined for the map and for the retention of anomalous data. Passing files to the “private platform” does not automatically complete information governance; actual user permissions and vendor rules determine who can access the data.

Specific Scope of Actions to Clean Up Historical Data After Policy Changes

Change from public maps to private maps, listing the map addresses associated with the old hash scripts, historical deployment entries, and potential embedded maps. The new version does not include sourceMappingURL and will not delete old files. After cleaning up public storage and CDN objects, directly request the addresses in the list and verify whether the mapping content is still available. The platform may retain historical deployments, and its access policies should also be checked, rather than only accessing the current main domain.

However, once the source code has been downloaded, it cannot be retracted. If the change is simply a modification to the information release policy, the scope of continued public disclosure and any remaining restrictions should be adjusted accordingly. If credentials exist, the corresponding capabilities should be immediately revoked. Deleting the map and revoking the secret address address different issues. Do not directly post all historical filenames in the public incident report to expand the spread; the internal list is sufficient to support disposal, and the external report should only provide necessary information.

Future rules are written into the product classification steps to prevent re-uploading old files in the future. After cleaning, if the local files are modified without modifying the deployment pipeline, the files may still be publicly accessible. This creates two layers of evidence: the negative product assertion and the real access check. The file is not on the public list, and the route does not provide it. The address 404 does not cover the embedded data or alias path, so a list-driven approach is needed instead of guessing a suffix.

Information Categorization Check: Not Just Searching by Key Name

The sourcesContent within the mapping may contain unexecuted module comments, personal directories, and internal feature plans. The build process’s tree shaking may not necessarily remove all of this text. When checking the final JSON’s sources against sourcesContent, and processing based on the approved information categories for each project, it’s important to note that you cannot infer file content based solely on the page’s functionality. Path normalization is performed during the generation stage to avoid manual replacements that could break the file and mapping relationship.

You can use synthetic usernames, internal host sentinel, and fake secret construction testing modules to check if they are entering the public output. Real-world secret scanning requires dedicated tools and controlled output; it’s not practical to write values directly into the terminal for ease of searching. The reports should identify the location and fields of the secrets, without repeating the full secrets. Licenses and publicly available comments have their own compliance requirements, and you should not delete all text simply to clear information.

Private mapping tests require verification of multiple conversion chains. TypeScript transpilation, framework compilation, and compression may each generate mappings, and if the final merge fails, the JSON remains valid but is located in an intermediate output. Select a controlled function that has gone through these stages, and check the files, rows, and source content, not just the exception names. If the sourcesContent mapping is missing, the platform may have separate source files, and you need to supplement them according to the tool’s contract. Without assuming that the format is valid, you will have the ability to fully restore it.

Explicitly Document Reduced Debugging Capabilities in Release Results

When a private upload fails, if the policy allows continued publication, report the new version’s release but indicate that source code restoration is not yet ready, and save the accurate output for retry. Do not subsequently regenerate the map as a workaround, nor mark the entire process as complete. Key systems can choose to halt deployment, based on maintenance needs and risk assessment. Regardless of the policy, the failure state has a clear recovery action, rather than simply swallowing the error.

After publication, controlled anomaly verification was performed to restore the original state, and the public range was verified to still comply with the policy. The anomalous samples did not contain user data, and the triggering entry was closed after the test. The final report covers four aspects: public classification, actual upload, accurate restoration, and historical processing, providing verifiable evidence for both debugging and information scope.

Validation of Mapping Format and Behavior Verification: A Complementary Approach

A valid JSON file does not guarantee accurate mapping. The sources, mappings, and file versions must match, and whether the original source content is embedded also depends on the generated configuration. It is important to use established tools to read the mapping, select a known compression location to restore to the expected source location, and avoid parsing complex encodings yourself. In particular, if the configuration involves multiple transformations, it is crucial to ensure that the mapping chain is correctly merged, such as re-compressing TypeScript after translation.

You can trigger a synthetic exception within a controlled function in a preview version, and clearly document the expected behavior in the source code. The event should be directed to the correct project and environment, displaying the correct file and location. Do not trigger errors using real user secrets, and do not leave test exceptions in the production normal path. This experiment, which verifies the complete upload, versioning, and rollback process, is more reliable than simply checking for “several map files” in the monitoring backend.

Additionally, directly request the public mapping address for the prediction, including the script link’s target location and common paths with the same name. If the policy requires private access, the public mapping list should not contain these files, and accessing it should not return the mapping content. Just getting a 404 is not enough; check for alternative asset paths or embedded content. The scan and access tests should cover both the existence and actual routing behavior of the files.

When debugging a rollback, preserve the original location and avoid guessing the source code to fill in the gaps. In some cases, only the file’s row number is available; the interface should clearly indicate that the asset has not been restored, and maintain the accurate asset identity and security error category. Do not replace the source code location with another version of the same function name. Error aggregation should not automatically include “unknown source code location” within a known exception; otherwise, it will be impossible to determine the extent of the impact of the previous failures after uploading and restoring.

It is possible to save two versions of the synthesized event: one from the uploaded version and one from the unuploaded version. The first version restores the original state, while the second version explicitly preserves the compressed location. Subsequently, the second version’s accurate mapping is updated, and the platform is observed to support re-processing historical events. If the platform does not support this, the limitation is recorded, and a new event is used to verify, without promising that the old reports will automatically be fixed. This allows for a realistic debugging state, rather than simply observing the number of uploaded files.

When the recovered source code contains sensitive comments, sharing the incorrect link will also expand the scope of the information. External issue reports should only retain the necessary function behavior, version, and de-identification stack. Monitoring backend links should be handed over to authorized personnel. An event attachment, originally private, does not necessarily mean that exporting or taking screenshots will still inherit the permissions. Before handing over, verify the actual sharing object to avoid correct private uploads being inadvertently made public in subsequent troubleshooting.

References: MDN sourceMappingURL, Vite build options.