How a Misbundled Source Map Leaked an AI Coding Agent's Source Code: Causes, Architecture, and Prevention

    This article analyzes a source code leak caused by accidentally publishing a source map from a command-line AI coding agent. It explains how source maps and sourcesContent can reconstruct minified client bundles, the five build, packaging, audit, storage, and credential controls that failed, and the exposed architecture of agentic coding tools, including query engines, tool layers, subagents, memory, editor bridges, and command systems. It also assesses the security risks of client-side source disclosure and provides a practical hardening checklist for release gates, artifact audits, storage policies, and incident response.

    Incident Overview: How a .map File Exposed Source Code

    A recent incident involving a command-line AI coding agent exposed a large amount of source code because source map files were accidentally included in the published release package. Since these mapping files can inline original source code, or contain URLs pointing to internal object storage buckets, external parties were able to reconstruct roughly 1,900 source files and more than 510,000 lines of code. After the incident was first disclosed on social platforms, complete mirrors and community-written architecture breakdowns appeared quickly.

    According to public information, the leaked material was mainly client-side implementation code. It did not include model weights, training data, server-side logic, or user data. This distinction matters: the incident is primarily an issue of intellectual property and architecture exposure, not model theft or data breach. However, for client-side engineering, the leak still exposed prompt templates, permission validation logic, built-in tool inventories, internal threshold parameters, and unreleased features.

    The speed of response also matters. The package was quickly updated and the mapping files were removed, but by then mirrors and secondary distribution had already occurred. This leads to a basic conclusion: once source code is on the public internet, removal can only stop incremental spread; it cannot recover content that has already been copied. Defense must therefore move from post-release takedown to pre-release blocking.

    How Source Maps Turn Minified Bundles Back into Source

    To understand the incident, it is necessary to understand what source maps are designed to do. Modern frontend and Node.js toolchains usually perform three steps: transpilation, bundling, and minification. TypeScript is compiled to JavaScript, multiple modules are combined into a few bundles, and identifiers are renamed while whitespace is removed. The result runs efficiently, but is difficult to debug. In production error stacks, developers may only see names like a.b.c along with a line and column number.

    A source map acts as a restoration map for this process. It is a standalone JSON file. Its core fields include:

    1. {
    2. "version": 3,
    3. "file": "cli.bundle.js",
    4. "sources": ["https://<object-storage-public-url>/pkg/src/engine/queryEngine.ts"],
    5. "sourcesContent": ["/* full original TypeScript source ... */"],
    6. "names": ["runQuery", "streamResponse", "countTokens"],
    7. "mappings": "AAAA,SAASA,cAAc,..."
    8. }
    • sources: a list of original file paths. If the build used absolute paths or paths with domains, this field can directly expose internal build directory structures or even storage addresses.
    • sourcesContent: the full original source code. This is the key factor in leakage because it makes the source map self-contained. Even without access to the repository, the original code can be reconstructed.
    • mappings: a sequence of Base64 VLQ-encoded segments. It describes how each location in the generated code maps to a specific line and column in a source file.
    • names: original identifiers before minification. This effectively undoes any obfuscation performed during the build.

    Whether source code is leaked does not depend primarily on whether the code was obfuscated. It depends on two things: whether the map file is distributed with the artifact, and whether sourcesContent is inlined.

    Consuming a source map is technically simple:

    1. // Demo: read a .map file next to the output and extract embedded source content
    2. import { readFile } from 'node:fs/promises';
    3. const map = JSON.parse(await readFile('dist/cli.bundle.js.map', 'utf8'));
    4. console.log('Source file count:', map.sources.length);
    5. console.log('Inline source content:', Boolean(map.sourcesContent));
    6. map.sources.slice(0, 5).forEach((p) => console.log(' -', p));

    In other words, the attack barrier is almost zero: download the package, unpack it, traverse all *.map files, and read sourcesContent. This process is much simpler than most common intrusion techniques, which helps explain why such incidents often have a large and rapidly expanding impact.

    How the Failure Chain Happened: Five Controls Broke at Once

    Security incidents are rarely caused by a single mistake. This one also involved at least five controls that should have worked but did not:

    1. Build configuration: transpilers generated source maps by default. Release mode did not disable them, or the build used inlineSourcesContent, embedding source code directly into the map.
    2. Missing artifact allowlist: the package manifest relied on an ignore list, such as excluding tests and documentation. Because the .map files were located inside the dist directory that needed to be published, they were included unintentionally. Relying on what to exclude rather than what to include is the leading cause of this type of incident.
    3. Missing artifact audit: the release pipeline did not scan the final tarball. There were no automated gates for .map files, internal domains, secret strings, or absolute paths.
    4. Improper object storage permissions: the object storage address recorded in the source map was publicly readable, effectively providing a direct download path for the leaked content. Object storage buckets should be private by default. External distribution should use short-lived signed URLs or a controlled content-delivery configuration.
    5. Credential and endpoint management: if any access token or internal endpoint appears in a build artifact, it must be treated as leaked and rotated immediately, rather than evaluated based on assumptions about whether anyone saw it.

    In mature teams, all five areas are converted into strict constraints with a default-deny principle.

    Architecture of Agentic Coding Tools Exposed by the Leak

    The leaked source code unexpectedly exposed the internal structure of this type of AI coding tool. Setting aside product-specific details, the architecture is highly generic and useful for anyone building a code agent.

    Query engine: the control center of the tool

    The core component is a session or query engine. Its responsibilities include receiving user instructions, determining task type, deciding whether to enter an autonomous loop, assembling context, calling model APIs, handling streaming output, maintaining prompt caches, decomposing multi-step tasks, and chaining tool calls. The most important engineering component is the loop:

    1. while (task incomplete && step limit not reached) {
    2. response = callModel(context + tool list + recent tool results)
    3. if (response contains tool calls) {
    4. check permissions -> execute tool -> normalize result -> append to context
    5. } else {
    6. emit final answer; break
    7. }
    8. count tokens; if threshold exceeded, compact or trim context
    9. }

    Several engineering details determine whether the tool is actually usable: retries with exponential backoff, rate-limit handling, context window management and history summarization, thinking or extended-reasoning budget control, token counting and cost estimation, and interruption and cancellation signaling. Mature implementations are usually thousands or tens of thousands of lines long. In the leaked file list, QueryEngine.ts was reported to be about 46,000 lines and Tool.ts about 29,000 lines, showing that real complexity is concentrated in error handling and state management rather than in the single line that calls the model.

    Tool layer: enabling the model to take action

    Conversation alone cannot complete engineering tasks. The tool layer provides action capabilities: file reading, writing, and editing; codebase semantic and full-text search; shell command execution; network requests; and subtask dispatch. Each tool requires three things:

    • Input schema: structured parameter definitions, equivalent to JSON Schema, used both to help the model understand the tool and to validate inputs.
    • Permission model: classified authorization for read, write, execute, and network access, combined with user confirmation, directory allowlists, and command denylists.
    • Progress and result protocol: streaming progress events, truncatable large outputs, and structured errors to prevent context from being flooded with irrelevant content.

    Editing tools are especially important. Replacing exact strings is more token-efficient and more reliable than rewriting an entire file, but it can also fail more often. In practice, a combination such as “read first, match exactly, then fall back to line-level replacement if matching fails” improves the success rate.

    Subagent collaboration

    For large codebases, a single context cannot contain all required information. This is why multi-agent or swarm patterns appear. A main agent handles task decomposition and result integration, while subagents complete subtasks such as retrieval, review, and testing in independent contexts and return only summaries. The benefits are context isolation and parallel acceleration. The cost is coordination overhead and result consistency issues. If a summary loses critical details, the main agent may make incorrect decisions, so the output contract of each subtask must be strict.

    Memory and context persistence

    Cross-session capabilities depend on a memory system: session histories are persisted to disk, project-level memory files are maintained through conventional directories and instruction files, hierarchical rules are loaded by path, and code snippets are recalled using vector retrieval. The design principle is “explainable, editable, and invalidatable”: memory should be reviewable and correctable like configuration files, not treated as a black box.

    Editor bridge

    As a command-line tool, it needs bidirectional communication with mainstream code editors and IDEs: receiving selected code and diagnostics, then writing back files and diff views. Cross-process communication usually involves a local service, a conventional port, and token authentication, such as a signed token similar to JWT. The security requirement here is critical: the local listening port must validate the source, restrict the bind address, and use short-lived tokens. Otherwise, it effectively becomes a local command execution entry point.

    Command system and extension points

    Slash commands, subcommands, custom prompt templates, lifecycle hooks for intercepting tool calls before and after execution, and standardized protocols for connecting external tools or data sources together form the extensibility layer. The command system itself is also a permission risk area. If custom commands allow shell string concatenation, command injection becomes highly likely.

    Risk Assessment: What to Worry About After Source Code Is Public

    The direct consequence of client-side source code leakage is the disappearance of information asymmetry between attackers and defenders. Specific risks include:

    • Permission bypass paths become discoverable: client-side confirmation dialogs, directory allowlists, and command filtering logic are all visible. Attackers can construct inputs that pass validation or modify the client to remove validation.
    • Protocols and endpoints become exposed: internal API shapes, authentication methods, and caching strategies become known, making it easier to forge requests, abuse quotas, or conduct further probing.
    • Prompt engineering can be copied: system prompts, tool descriptions, and few-shot examples can be fully reproduced, erasing product differentiation.
    • Unreleased features are exposed early: roadmaps and unfinished capabilities can be interpreted by others, affecting release timing and competitive position.

    This leads to a more important design conclusion: the client is never a trust boundary. Any security design that depends on “the client will constrain itself” should be considered ineffective. The correct approach is to move policy enforcement downward: tool execution should undergo secondary authorization on the server, tokens should be issued with least privilege and short lifetimes, outbound traffic should pass through a controlled proxy with audit logs, and high-risk commands should use sandbox isolation and resource limits. If these measures are already in place, the harm caused by source code leakage can be significantly reduced.

    Hardening Checklist: Practical Engineering Constraints

    Artifact allowlists and source map policy

    • Disable source map generation in release mode, or generate maps but do not package them. If debuggability must be retained, use maps without sourcesContent, and ensure source paths do not contain internal directories or domains.
    • Use an allowlist in the package manifest. Explicitly declare the files and directories that should be published. Any newly added artifact should require manual confirmation before entering the release scope.
    • If production error stack restoration is required, upload source maps to a private error monitoring backend and perform symbolication on the server. Never ship them to the client with the package.

    Pre-release artifact audit: the most critical gate

    1. // scripts/audit-artifact.mjs — run after packaging and before upload in the release pipeline
    2. import { readdir, readFile, stat } from 'node:fs/promises';
    3. import { join, relative } from 'node:path';
    4. const ROOT = 'dist';
    5. const FORBIDDEN_EXT = ['.map'];
    6. const SECRET_PATTERNS = [
    7. /AKIA[0-9A-Z]{16}/, // common access key pattern
    8. /-----BEGIN [A-Z ]*PRIVATE KEY-----/, // private key
    9. /eyJ[\w-]{10,}\.[\w-]{10,}\./, // JWT-like token
    10. ];
    11. const findings = [];
    12. async function walk(dir) {
    13. for (const name of await readdir(dir)) {
    14. const p = join(dir, name);
    15. if ((await stat(p)).isDirectory()) { await walk(p); continue; }
    16. const rel = relative(ROOT, p);
    17. if (FORBIDDEN_EXT.some((e) => p.endsWith(e))) findings.push(`[map] ${rel}`);
    18. if (/\.(js|mjs|cjs|json|ts)$/.test(p)) {
    19. const text = await readFile(p, 'utf8');
    20. for (const re of SECRET_PATTERNS) if (re.test(text)) findings.push(`[secret] ${rel}`);
    21. // inline source map: map content embedded in artifact as base64
    22. if (/sourceMappingURL=data:application\/json;base64/.test(text)) findings.push(`[inline-map] ${rel}`);
    23. // internal build directory or storage address leakage
    24. if (/\/home\/[\w-]+\/build|\/build\/agents?\//.test(text)) findings.push(`[path] ${rel}`);
    25. }
    26. }
    27. }
    28. await walk(ROOT);
    29. if (findings.length) {
    30. console.error('Release gate failed:');
    31. for (const f of findings) console.error(' -', f);
    32. process.exit(1);
    33. }
    34. console.log('Artifact audit passed');

    Additional requirements: the gate should be blocking, meaning a failed check immediately aborts the release. Audit results should be retained as build logs. For high-risk patterns, pre-commit hooks should also be configured to catch problems earlier in the development process.

    Storage and distribution

    Object storage buckets should be private by default, directory listing should be disabled, and access logs should be enabled. External distribution should use short-lived signed URLs or a controlled content-delivery configuration. Lifecycle policies should be configured for historical objects to prevent retired artifacts from remaining accessible for a long time. For general-purpose cloud storage services, such as Baidu AI Cloud or other major cloud providers, the same principles apply: default deny, least privilege, and full audit. Bucket policy changes should also be included in the configuration review process.

    Credentials and incident response

    • Any token, certificate, or internal endpoint that has entered a build artifact should be treated as compromised and rotated immediately.
    • Establish an incident response process: release a fixed version, revoke old versions, remove high-risk artifacts, collect access logs for impact assessment, and request takedowns of third-party mirrors from hosting platforms under applicable legal procedures.
    • During post-incident review, assume the threat model is “the source code is already public.” Reassess the permission model and server-side defenses rather than simply patching a packaging configuration.

    Conclusion: Do Not Treat Invisibility as a Security Assumption

    This incident was not technically complex: a .map file, a publicly readable address, and a missing artifact audit. However, it exposes a common problem: many engineering teams treat “the code cannot be seen” as part of their security capability, while build systems often default to “package more” rather than “package less.”

    For enterprise users adopting this type of AI coding agent, three points are worth remembering. First, the client of an AI coding assistant is an attack surface, not a security boundary. Permission control must be enforced on the server and in the runtime environment through sandboxing, egress control, least-privilege tokens, and audit logs. Second, when procuring or building such tools, teams should include regular checks such as whether release artifacts contain source maps, whether secret scanning is integrated into the pipeline, and whether artifact provenance is verifiable. Third, after a leakage incident, the correct posture is to redesign under the worst-case assumption, not merely patch a single configuration item.

    Source code visibility should never be the moat. Maintainable architecture and a rigorous permission model are.