乐于分享
好东西不私藏

Claude Code 源码泄露?别慌,先搞懂什么是 Source Map

Claude Code 源码泄露?别慌,先搞懂什么是 Source Map

学友们,昨天(2026年3月31号)发生了一件特别魔幻的事。

Anthropic 的 Claude Code——就是现在最火的 AI 编程工具之一——它的源码,泄露了。

不是被黑客攻破的,不是内鬼偷的。

是自己人,在发 npm 包的时候,把 source map 文件打进去了

一个 59.8 MB 的 .map 文件,安安静静地躺在 @anthropic-ai/claude-code 的 2.1.88 版本里。

被安全研究员 Chaofan Shou 发现后,不到一个小时,这份代码就被扒得裤子都不剩了。

51.2 万行代码,大约 1900 个文件,全部曝光。

Anthropic 官方回应:这是”发布打包环节的人为失误”,不是安全漏洞,不是黑客攻击。

好家伙。


Source Map 到底是个啥?

好,我们先把 Claude Code 放一边,来聊聊这个”幕后凶手”。

Source Map,翻译过来就是”源代码映射”。

它是一份 JSON 格式的文件,干的事情用一句话概括就是——

把编译后乱七八糟的代码,映射回你原来写的源代码。

为啥需要这东西?

因为现代前端开发有一个”潜规则”:你写的代码,和浏览器跑的代码,根本就不是同一份。

你用 TypeScript 写的,它要编译成 JavaScript。 你用了 ES2025 新语法,它要转译成 ES5 兼容版。 你写了 50 个文件,webpack 给你打成 1 个 bundle。 你变量名叫 userController,打包后可能变成了 a

这叫什么?这叫转译 + 压缩 + 混淆

好处是:文件更小,加载更快,别人想抄你的代码也费劲。

坏处是:线上出了 Bug,你看到报错信息写着 Error at a.b.c line 1 column 38291——

你能debug个啥?

这不是debug,这是破案。

Source Map 就是你的”破案地图”。

它告诉浏览器的开发者工具:”喂,这个压缩后的第1行第38291列,对应的其实是原始文件 src/controller/user.ts 的第42行第5列。”

有了它,你打开 Chrome DevTools,看到的就是你自己写的 TypeScript 源码,而不是那坨天书。

打断点、看调用栈、定位错误,全部丝滑。

这就是 Source Map 的设计初衷:让你在生产环境出了问题的时候,还能像在本地一样 debug。

什么场景会用到?

基本上,只要你用了构建工具,就离不开 Source Map:

  • Webpack / Vite / esbuild 打包时生成
  • TypeScript → JavaScript 编译时生成
  • Babel 转译 时生成
  • CSS 预处理器(Sass/Less → CSS)也会生成
  • 错误监控平台(Sentry、Bugsnag)需要它来还原线上报错的可读堆栈

简单说:Source Map 不是前端独有的概念,但它在前端生态里,是基础设施级别的存在。


Source Map 文件里到底有什么?

好,现在你知道它是一张”映射地图”了。

那这张地图里,具体写了些啥?

打开一个 .map 文件,你会看到一个 JSON,里面有这几个关键字段:

{
"version"3,
"file""bundle.js",
"sourceRoot""",
"sources"["../src/index.ts""../src/utils/helper.ts"],
"sourcesContent"["const x = 1;...""export function helper()..."],
"names"["x""helper""console""log"],
"mappings""AAAA,IAAM,CAAC,GAAG..."
}

一个一个来:

version

永远是 3。Source Map 规范目前就到第三版(已经被纳入 ECMA-426 标准)。就像你去银行填表,格式版本号永远写在最前面。

file

生成文件的名字。就是那个压缩后的 bundle.js。告诉你”这张地图对应的是哪份代码”。

sourceRoot

源文件路径的前缀。比如你原始文件都在 src/ 目录下,这里就写 src/,后面 sources 里面就不用每个都重复写了。

sources

重头戏来了。

这是一个数组,列出了所有原始源文件的路径。

比如你有 50 个 TypeScript 文件被打成一个 bundle,sources 里就会有 50 个路径。

sourcesContent

泄露的关键。

这个字段直接把原始源代码的文本内容内嵌进来了。

对,你没看错。不是路径,是代码本身

为什么要这么做?因为有时候你的原始文件不在线上(比如你只部署了 bundle.js),但调试工具需要显示源码。那怎么办?直接把源码塞进 map 文件里。

Claude Code 的 59.8 MB 的 .map 文件,就是因为 sourcesContent 里塞了 51.2 万行 TypeScript 源码,才这么大。

这就好比:你给快递贴了一个标签条(mappings),但你在标签条上直接打印了包裹里所有东西的照片和细节清单(sourcesContent)。

快递员一看标签就知道你里面全是啥了。

names

原始代码中的标识符名称列表。变量名、函数名、类名。

因为压缩后 userController 变成了 a,这个列表就是”a 先生的真名叫 userController”的翻译表。

mappings

最硬核的字段。

这是一串用 Base64 VLQ 编码的字符串,看起来像乱码:

AAAA,IAAM,CAAC,GAAG;AACN,SACA...

但它其实记录了每一个代码位置的映射关系。

简单解释一下规则:

  • 分号 ; 分隔行:每个 ; 代表生成文件中的一行
  • 逗号 , 分隔段:每个 , 代表同一行中的一个映射点
  • 每个段包含 4 或 5 个数字(用 VLQ 编码),分别表示:
    1. 生成文件中的列号
    2. 对应哪个源文件(sources 数组的索引)
    3. 原始文件中的行号
    4. 原始文件中的列号
    5. (可选)对应哪个标识符(names 数组的索引)

而且所有数字都是相对上一个段的偏移量,不是绝对值。这样可以极大压缩体积。

为什么用 Base64 VLQ 而不是直接写数字?

因为一个大型项目的映射点可能有几十万到上百万个。如果每个都用 JSON 数组 [12, 3, 42, 5] 来表示,文件大小会爆炸。VLQ 编码把它压到了极小。

打个比方:mappings 就是一本超级压缩的”坐标手册”,告诉你生成代码的每个位置,对应原始代码的哪个位置。


用 Source Map 还原代码:到底怎么操作的?

好了,现在你理解了 Source Map 的结构。

那回到 Claude Code 这个事件——安全研究员是怎么”一键还原”几十万行源码的?

其实,流程没你想象的那么复杂:

第一步:拿到 .map 文件

从 npm 下载 @anthropic-ai/claude-code@2.1.88 这个包,解压后发现里面有个 cli.js.map,59.8 MB。

正常的 npm 包不会包含 map 文件——这是 Anthropic 打包时的失误,忘了在构建配置里排除它。

第二步:检查 sourcesContent

打开这个 .map 文件(虽然 60MB 的 JSON 打开有点费劲),看 sourcesContent 字段。

如果这个字段有值,那整个源代码就已经在你眼前了。不需要任何”破解”。

Claude Code 的情况更刺激:这个 map 文件里甚至包含了一个指向 Anthropic Cloudflare R2 存储桶的链接,桶里放着打包好的源码 zip 压缩包。

直接下载,解压,搞定。

连 Source Map 的映射都不需要手动解析,人家直接给你提供了原始文件的下载链接。

这操作……怎么说呢,有点像你在门上装了一个密码锁,然后在门把手上贴了一张纸条,写着:”密码是123456″。

第三步:如果没有 sourcesContent 呢?

如果 map 文件里只有 sources(路径列表)和 mappings(映射编码),没有内嵌的源码内容,那你就需要用工具来还原了。

常用的工具有:

  • source-map npm 包:Mozilla 官方出的 JS 库,能解析 map 文件并根据映射关系重建源码结构
  • shuji:一个专门用来从 Source Map 还原源码的命令行工具
  • reverse-sourcemap:类似功能
  • Chrome DevTools:直接打开浏览器开发者工具,加载 map 文件,浏览器会自动帮你还原

还原过程的本质是:

  1. 解析 mappings 中的 VLQ 编码,得到所有映射点
  2. 根据映射点和 sources 中的文件路径,创建目录结构
  3. 根据映射关系,把压缩代码中的每个字符/标识符对应回原始文件的位置
  4. 重建出原始文件

如果有 sourcesContent,直接提取就行,连映射都不用管。就是白送。

所以你看:Source Map 的”泄露”不是什么黑客技术,它根本就是按照设计意图工作的。 它本来就是为了让你还原代码而存在的,只不过它不应该出现在面向用户的生产包里。


Claude Code 不是有个官方仓库吗?泄露啥呢?

有学友可能会问:等会儿,Claude Code 不是本来就有个 GitHub 仓库吗?(github.com/anthropics/claude-code)

既然已经”开源”了,那泄露出来的有啥稀奇的?

稀奇大了。

官方仓库和泄露的源码,完全不是一回事

打个比方:

官方仓库,就像一家餐厅的菜单。你知道有什么菜,知道价格,知道怎么点单。

泄露的源码,是这家餐厅的后厨。你看到了配方、看到了厨师偷偷加的调料、看到了还没上市的新菜、甚至看到了厨房里贴着的”如果客人投诉就多加点味精”的小纸条。

具体来说:

官方仓库提供的是:

  • 安装指南、使用文档
  • CLI 的公开 API 和配置项
  • Issue 跟踪和变更日志
  • 基本的项目说明

泄露的源码暴露了:

  • 完整的 TypeScript 原始代码(51.2万行,1900个文件)
  • 内部 feature flag(功能开关)
  • 未发布的实验性功能
  • 安全与反竞争策略的具体实现
  • Prompt Engineering 的实际模板
  • 多 Agent 编排架构的完整细节
  • 内部遥测(telemetry)和用户行为追踪逻辑

这差距,大概就像”公司官网的团队介绍页” vs “公司内部飞书文档全库”。

一个是给你看的,一个是不想让你看的。


泄露的源码里,到底有哪些”让人直呼内行”的设计?

好了,接下来到了学友们最期待的环节——八卦时间。

我挑几个最有意思的来聊。

亮点一:多 Agent 协作——Coordinator 模式

Claude Code 内部有一个叫 Coordinator Mode(协调者模式) 的系统。

不是说”一个 AI 帮你写代码”那么简单。

它的架构是:一个总协调员(Coordinator),管着一群工人(Worker Agent)

协调员负责拆任务、分发工作、监控进度。每个 Worker 独立执行具体任务(读文件、写代码、跑测试等等)。

它们之间通过一个邮箱系统通信,还有一个共享草稿板(Scratchpad) 用来同步状态。

这不就是面向微服务的 AI Agent 架构吗?

你以为 Claude Code 是一个 AI 在帮你写代码,其实是一个项目经理带着一组程序员在帮你干活。 你只是看不到那些”程序员”而已。

亮点二:记忆系统——”严格写入纪律”

Claude Code 的记忆系统设计得非常硬核。

内部有个规则叫 Strict Write Discipline(严格写入纪律)——Agent 只有在成功写入并确认文件之后,才能更新自己的记忆索引。

为什么?因为 AI Agent 有”幻觉”问题——它可能”以为”自己干了某件事(比如写了一个文件),但实际没干成。如果让它不管成不成功都更新记忆,后面的操作就全乱了。

更骚的是,它还有个叫 autoDream(自动做梦) 的功能。

对,你没看错,”做梦”。

这是一个后台进程,在夜间自动运行,负责:整理一天积累的记忆、裁剪过时的信息、压缩冗余知识。

就像人类晚上做梦时,大脑在整理白天的记忆一样。

这个设计真的是拍案叫绝。

亮点三:KAIROS——永远不下班的 Agent

代码里有个被 feature flag 隐藏的功能,代号 KAIROS

普通的 Claude Code 是你”召唤”它来干活,干完就撤。

KAIROS 不一样,它是一个常驻后台的自治 Agent

它会持续监听 GitHub webhooks、定期巡检代码仓库、自动写日志——

有点像你给项目组里安排了一个”值班同学”,7×24小时盯着仓库,有 Issue 就自己去看,有 PR 就自己去 Review,凌晨三点代码出问题了它自己先去修。

而且它设计了一个 15 秒阻塞预算——意思是它在后台默默干活的时候,绝对不能阻塞你正在进行的交互操作超过 15 秒。

这就是”活好不粘人、帮忙不添乱”的终极形态。

亮点四:BUDDY——电子宠物???

好了,这个是最离谱的。

代码里居然有一个叫 BUDDY 的模块。

一个电子宠物系统。

类似”拓麻歌子”(Tamagotchi)。

18 种物种,还有稀有度和”闪光”变体。每只宠物有随机生成的属性,比如”混乱值”、”毒舌值”。还有 ASCII 动画。

根据代码注释,这个功能原定在 2026 年 4 月 1-7 号”预告”上线。

等等,4月1号……愚人节?

Anthropic 你是不是在整我?

不管是不是彩蛋,这个设计确实说明了一个问题:顶级工程团队在做严肃产品的时候,也不忘留点有趣的东西。 技术和趣味不矛盾。

亮点五:反蒸馏——给竞争对手”投毒”

这个设计属于”细思极恐”。

代码里有个叫 ANTI_DISTILLATION_CC 的 flag。

开启后,它会在系统提示词里悄悄注入一些假工具(Fake Tools)

什么意思?

如果有竞争对手在偷偷爬取 Claude Code 和 API 之间的通信流量,想用这些数据来训练自己的模型(业内叫”蒸馏”),那他们会把这些假工具一起训练进去。

结果就是:他们的模型会”学会”一些根本不存在的工具,然后在实际使用时出错——相当于你在答案里掺了假答案,抄你的人怎么抄都不对。

这招在学术界有个名字,叫**”canary trap”(金丝雀陷阱)**——在不同份文件里放不同的错误,追踪谁是内鬼。

不过,这个策略有个致命缺陷:它依赖保密。 一旦源码泄露(嗯,就是现在这样),全世界都知道你在注入假工具了,这招就废了。

有网友评论:”就像你在考试答案里写错误答案防抄袭,结果你的答案卷子被公开了。”

绝了。

亮点六:工具分级系统——40+工具的权限管理

Claude Code内部注册了 40 多个工具(Tool),按风险等级分成三档:

  • LOW:只读操作,比如读文件、搜索代码
  • MEDIUM:有一定副作用,比如修改文件
  • HIGH:高风险操作,比如删除文件、执行 shell 命令

更有意思的是,它还有一个基于 ML 的 YOLO 分类器——用来判断某些操作是否可以自动批准,跳过用户确认环节。

你没看错,分类器的名字就叫 YOLO。

“You Only Live Once,自动批了吧。”

当然,这个分类器只用在低风险操作上。高风险的还是得你手动确认。

否则 AI 一个 rm -rf / 帮你”优化”了磁盘空间,你哭都来不及。


聊聊这件事的”味道”

说完技术细节,咱们上点价值。

这件事最有意思的地方在于:大量网友认为,这是 Anthropic 故意泄露的。

理由很多:

  • 泄露时间选在 4 月 1 日(愚人节前夕),太巧了
  • 代码里的 BUDDY 电子宠物功能原定 4 月 1-7 号上线”预告”,时间对得上
  • map 文件里直接附了源码下载链接,这不像”失误”,更像”请帮我传播”
  • OpenAI 的 Codex(github.com/openai/codex)是真开源的,但社区讨论度远不如这次”泄露”——说明得不到的永远在骚动,免费的谁也看不上

Anthropic 对此的回应永远是那句:”人为失误,不是安全漏洞。”

但你看——

51.2万行代码,1900个文件,结构清晰,注释完整,连未发布功能的彩蛋都安排上了。

如果这真的是”失误”,那这可能是人类历史上最体面的失误。

我不站队。

但我想说一个很有意思的现象:当你的代码质量足够好、架构足够优雅的时候,就算你”不小心”泄露了它,别人也不觉得这是事故,而觉得这是炫技。

反过来也成立:你有时候精心设计了一个很巧妙的功能,结果用户以为是 Bug。

说到这里我自己都破防了。

想起了之前在平台项目里加小设计被用户当成 Bug 的经历。

在绝对的实力面前,你真的写了一个 Bug,别人也觉得是feature。在不够强的时候,你特意写了一个 feature,别人也觉得是 Bug。

这就是”泄露”和”开源”的本质区别。

不是代码公不公开的问题,是你在别人心里到底有多强的问题。


最后说两句

Source Map 本身不是什么高深的东西。

它的设计规范已经写进了 ECMA-426。它的格式十年前就定了。每天有几百万的前端开发者在用它调试代码,没人觉得它有什么特别。

但就是这么一个”平平无奇”的技术产物,因为出现在了不该出现的地方(生产环境的 npm 包里),直接引爆了全网。

技术本身没有善恶,它出现的位置决定了一切。

菜刀放在厨房里是工具,放在大街上就是凶器。Source Map 放在开发环境里是调试利器,放在生产包里就是源码泄露的导火索。

所以,下次你发布 npm 包的时候,记得检查一下:

  • 你的 .npmignore 文件写了没?
  • 你的构建脚本里 devtool 配置是不是设成了 hidden-source-map 或者干脆关了?
  • 你的 sourcesContent 有没有在生产构建中被剥离?
  • 你的 CI/CD 流水线有没有一个步骤专门检查产物体积是否异常?

Claude Code 的工程师们写了 51.2 万行精美代码,但出了问题的地方,就一行配置。

最危险的Bug,往往不在你最复杂的代码里,而在你最不在意的角落里。

学友们,共勉。


如果你觉得这篇有帮助,给我点个赞吧。你的每一个赞,都是我肝下一篇的动力。

我是幽皇,我们下篇见。