Source Map Leaks: A Practical Guide to Artifact Release Security

    When a CLI tool's published package shipped with its Source Map files, roughly 512,000 lines of source code across more than 1,900 files became publicly readable within hours. This article walks through how Source Maps reverse minified output back to readable code, why a leak is not the same as open-sourcing, how to audit your own release artifacts, how to fix the gap across five layers, what to do in the first 24 hours after a confirmed leak, and how to turn the lessons into pipeline gates.

    1. Incident Postmortem: How a Config Slip Put Source Code on Display

    The technical chain behind this incident was remarkably short. An AI coding tool’s command-line client was published to a public package registry, and the compiled artifacts included the Source Map files, along with a comment at the end of each bundle pointing at them. Anyone holding the published package could reconstruct output that had been minified into unreadability back into source code complete with original file names, original variable names, and even the original comments — internal project code names, unreleased feature plans, internal API paths, and a large volume of development comments included.

    The scale was just as striking: more than 1,900 files and roughly 512,000 lines of source code were fully exposed, and within hours a wave of third-party mirrors, aggregator sites, and cloned repositories appeared. Trending metrics spiked almost immediately and online discussion escalated fast.

    One misconception that gets repeated constantly needs correcting first: a leak is not open source. Code being seen, copied, and starred does not carry any license grant with it, nor does it change who owns the code legally. For the party that exposed it, the only correct move is to treat it as a security incident — not to conveniently announce “we’re open sourcing now.”

    The most alarming part of this event is that nothing was breached. No defense-in-depth layer was broken. A check that should have existed at the release step was simply missing.

    2. The Mechanics: How Source Maps Reverse Minified Output Back to Readable Source

    1. File Structure and Key Fields

    A Source Map (the industry-standard spec is Source Map Revision 3) is essentially a JSON document. Its core fields:

    Field Purpose Leak Risk
    version Spec version, typically 3 None
    file Name of the output file it maps Low
    sources Paths of the original source files Medium (exposes directory layout, module boundaries)
    sourcesContent The complete text of the original source, embedded in the map Very high
    names Original identifiers before minification Medium (readability largely restored)
    mappings VLQ-encoded mapping string from output positions to source positions High (combined with the field above, allows line-by-line reconstruction)

    What actually defeats minification is the combination of sourcesContent and mappings: the former supplies the source text directly, the latter tells a browser debugger what each line and column in the output should be displayed as. With both present, reconstruction is nearly lossless.

    2. How mappings Is Encoded

    mappings separates lines in the output with semicolons and multiple mapping segments within a line with commas. Each segment consists of 1, 4, or 5 Base64 VLQ values, meaning in order: “output column offset,” “source file index,” “source line offset,” “source column offset,” and “original identifier index.” The decoding logic itself is under twenty lines:

    1. B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    2. def decode_vlq(seg: str):
    3. values, shift, acc = [], 0, 0
    4. for ch in seg:
    5. digit = B64.index(ch)
    6. cont = digit & 32
    7. digit &= 31
    8. acc += digit << shift
    9. if cont:
    10. shift += 5
    11. else:
    12. sign = acc & 1
    13. acc >>= 1
    14. values.append(-acc if sign else acc)
    15. acc, shift = 0, 0
    16. return values
    17. # Pseudocode: walk mappings and reconstruct "output position -> original file/line/column"
    18. for out_line, group in enumerate(mappings.split(";")):
    19. src_idx = 0
    20. for seg in filter(None, group.split(",")):
    21. fields = decode_vlq(seg)
    22. # fields[0]=output column fields[1]=source file index fields[2]=source line fields[3]=source column
    23. record(out_line, fields[0], sources[fields[1]], fields[2], fields[3])

    This point matters: as long as the map file is reachable on the public internet, your code has no “minification” protection at all.

    3. Three Common Leak Paths

    1. Map files shipped inside the package. The publish manifest used overly permissive include rules (for example, the entire dist directory), and .map files were bundled and uploaded.
    2. A comment in the artifact pointing to a public URL. Even if the map is not published with the package, a trailing //# sourceMappingURL=https://.../xxx.js.map comment leads an attacker straight to the hosting site, docs site, or static asset domain.
    3. Indirect exposure. Build archives, CI logs, attachment queues in error-reporting SDKs, and uploading maps to publicly readable buckets — any of these can make a map reachable from outside the package.

    AI coding tools are especially sensitive to this class of risk, because the source often layers on additional material: full system prompts, tool and function-call definitions, model routing and fallback strategies, quota and rate-limiting rules, and internal service endpoints. These are core product differentiators, not implementation details where “taking a look does no harm.”

    3. Quantifying the Risk: What Source Exposure Actually Costs

    • IP and business logic leakage. Algorithm implementations, tuning parameters, and cost models become plainly visible, letting competitors replicate them cheaply.
    • Credential and infrastructure exposure. Hard-coded tokens, internal domains, internal network addresses, debug flags, and allow-list IDs frequently hide in branches that were “never supposed to ship.”
    • A significantly larger attack surface. Auth check ordering, anti-debugging conditions, hidden switches, and license validation locations all become public; vulnerability research drops from black-box guessing to white-box reading.
    • Compliance and contractual risk. Confidentiality clauses in customer contracts and open-source license obligations (particularly third-party dependency notices in bundled output) may create joint liability.
    • Supply-chain contagion. Once an attacker confirms hard-coded credentials in a given version, they can spread laterally along the dependency graph.

    The conclusion is direct: protecting source code is not a substitute for security controls, but leaving source code naked invalidates the assumptions behind every other security design.

    4. Self-Audit: Confirm in Five Minutes Whether Your Artifacts Are Naked

    Run these five steps as a real audit. Do not rely on what the build log claims about itself.

    Step 1: Audit the pending publish manifest. Use your package manager’s publish dry-run to generate the complete file list that will actually go into the package, then confirm line by line that there are no .map files, no raw *.ts files, and no test or snapshot directories.

    Step 2: Scan the artifact contents. Run a full match over the build output directory. A hit on any of the following counts as risk:

    1. # 1) Does the artifact reference a source map (including inline data URIs)?
    2. grep -rEn "sourceMappingURL" ./dist
    3. # 2) Are map files themselves present?
    4. find ./dist -type f -name "*.map"
    5. # 3) Do the maps embed source text? (highest-risk item)
    6. grep -rl "sourcesContent" ./dist | xargs -r -n1 sh -c \
    7. 'echo "LEAK: $0"' | tee ./leak-report.txt
    8. # 4) Run a quick credential sweep while you're here
    9. grep -rEn "(sk|token|secret|password|api[_-]?key)\s*[:=]\s*['\"][A-Za-z0-9_\-]{16,}" ./dist

    Step 3: Verify anonymous reachability. From a machine with no connection to the internal network, request the artifact path for the released version and the xxx.js.map directly, and confirm whether it returns 200. This step covers the case where “the file is not in the package but the hosting site still serves it.”

    Step 4: Check historical versions and mirrors. A clean current version does not mean clean history. At minimum, cover the last N published versions, the docs site, demo environments, and the sync state of public mirrors and cache nodes.

    Step 5: Turn it into a gate. Wire these scripts in as a mandatory pre-publish checkpoint in the pipeline: on a hit, fail and block — not just warn.

    5. The Fix: Split the Defense into Five Layers

    1. Build Layer: Don’t Emit Readable Maps for Production

    The source map options in mainstream frontend/Node build tools can be summarized as follows:

    • Inline maps (base64-embedded): The artifact is self-contained and the leak risk is highest. Prohibited for external distribution.
    • Separate .map files plus a comment in the artifact: Usable, but you must guarantee the map never enters the package and never lands on a publicly hosted path.
    • Hidden maps (file generated, no comment written): Recommended for external distribution. The artifact contains no searchable clue, and the map stays under the team’s private control.
    • eval-family wrapping: Poor debugging experience and a possible source of extra execution risk. Not recommended.

    2. Release Layer: Allow-Lists, Not Deny-Lists

    Replace “exclude at publish time” with explicit include rules:

    1. {
    2. "name": "@your-org/your-cli",
    3. "files": ["dist/**/*.js", "dist/**/*.json", "README.md"],
    4. "publishConfig": { "access": "restricted" }
    5. }

    Pair that with two disciplines: ignore files (dot-prefixed ignore configs) tend to break as directories get reorganized, so prefer the files allow-list; and internal packages always go to a private registry with access control enabled — don’t push them to a public registry for convenience.

    3. Runtime Layer: Host Maps Behind Authenticated Error-Monitoring Infrastructure

    The correct posture is “artifacts to the whole internet, maps to the platform”: upload maps to your error-monitoring or logging service, exchange them via short-lived signed URLs or access tokens, and apply a file lifecycle policy to clean them up periodically. That preserves online stack-trace symbolication while denying anonymous readability to the map.

    4. Supply-Chain Layer: Visibility and Provenance Checks

    Produce and archive a software bill of materials (SBOM) for artifacts, verify the provenance of build inputs, forbid pulling dependencies from untrusted sources, and require a two-person review for release actions. Map governance belongs on the “release admission checklist,” alongside dependency vulnerability scanning and license checks.

    5. Cloud Implementation: Close the Loop With Generic Capabilities

    On Baidu AI Cloud, the full loop can be assembled from general-purpose building blocks: object storage in a private read-write bucket for source maps, with only time-limited signed links issued externally and lifecycle rules to clean up historical maps automatically; a logging service to receive online stack traces and symbolication results; monitoring and alerting triggered on events such as “a spike in map download requests” and “sourceMappingURL matches in artifacts”; and access controls in CI/CD pipelines and the artifact registry to harden the gate. These are combinations of generic capabilities and involve no vendor-proprietary implementation.

    6. Incident Response: The Golden 24 Hours After a Confirmed Leak

    Proceed on the assumption that the leak has already happened, not that it might have, and do not reorder the steps:

    • 0–2 hours | Stop the bleeding: Unpublish or deprecate the affected release and ship a fixed version; take down maps on the docs site, demo environments, and static hosting; purge CDN and cache nodes; revoke anonymous read access.
    • 2–6 hours | Scope the incident: Confirm the leaked file list, line counts, and version ranges involved, with priority on checking for hard-coded credentials and internal endpoints; assess disclosure obligations at the regulatory and contractual level.
    • 6–12 hours | Rotate credentials: Treat every token, certificate, and private key that appeared in the source as compromised and rotate all of them — no “evaluate and keep.” Order rotation by privilege level.
    • 12–24 hours | Fix and harden: Correct the publish configuration, wire artifact scanning in as a mandatory pipeline checkpoint, and rescan all historical versions.
    • After 24 hours | Communicate and review: Complete the external statement and internal postmortem, and assign owners and follow-up items. The key deliverable of a postmortem is not “be careful next time” but one pipeline rule that fails automatically.

    7. Broader Lesson: R&D Investment Must Grow Alongside Engineering Security

    The source material for this discussion also referenced share targets for large-displacement products in manufacturing and annual R&D investment on the order of 200 billion yuan at a telecom company. Both point to the same engineering rule: the higher the R&D intensity, the higher the value density of artifacts and source assets, and the larger the marginal loss from a leak. High investment without matching artifact governance puts your most expensive asset behind your thinnest door.

    Three metrics work well for measuring governance outcomes:

    • Map exposure convergence rate: The share of externally reachable .map files among all maps that should be produced. Target: 0.
    • Gate coverage: The share of artifact versions that passed pre-release scanning. Target: 100%.
    • Mean time to repair (MTTR): Time from scan alert to a completed fix and release. Aim for hours and track it in iteration reviews.

    8. One-Page Checklist

    • Production builds emit no inline source maps; external distribution uses hidden maps
    • The publish manifest is an allow-list, with .map files and raw source explicitly excluded
    • The published package contains no sourceMappingURL comment or inline data URI
    • Verified anonymously from an external network that both artifacts and maps are undownloadable
    • Maps are hosted centrally in an authenticated error-monitoring/logging service with short-lived links
    • No hard-coded credentials in source; secrets are issued by a dedicated secrets management service
    • The pipeline includes a mandatory scanning checkpoint that blocks a release on a hit
    • Internal packages go to a private registry with access control and least privilege
    • Artifact SBOM archiving and dependency provenance verification are in place
    • A written incident response plan exists, covering credential rotation order and external communication

    Making this checklist an automated check in the pipeline is more reliable than any postmortem. The baseline of source protection isn’t making code hard to understand — it’s making it impossible to obtain.