乐于分享
好东西不私藏

Claude Code 源码泄露始末:怎么泄的、怎么提的、怎么跑的

Claude Code 源码泄露始末:怎么泄的、怎么提的、怎么跑的

这两天 AI 圈最大的瓜,不是哪家又发新模型了,而是 Anthropic 把 Claude Code 的完整源码给泄了。

不是被黑客攻破,不是内鬼出卖,而是自己在发布 npm 包的时候,把源码的”对照表”一起打包发了出去。相当于卖手机的时候,把设计图纸和零件清单塞进包装盒寄给了用户。

花了两天研究整个事件的来龙去脉,顺便把源码提取、重建运行的过程摸了一遍。今天就来聊聊这件事。

━━━━━━━━━━━━━━━━

🔥 事件始末

3 月 31 日,安全研究员 Chaofan Shou 发了一条推文:Claude Code 的源码通过 npm 注册表里的一个 map 文件泄露了。

这个 map 文件有 59.8 MB。里面是完整的、未混淆的 TypeScript 源码——1900 个源文件,51.2 万行代码。

消息一出,GitHub 上几小时内就冒出了好几个镜像仓库,其中一个直接涨到了近 3 万 star、4 万 fork。传播速度比 Anthropic 的公关反应快多了。

Anthropic 赶紧做了三件事:更新 npm 移除 source map、删掉旧版本、给 GitHub 镜像发 DMCA 下架通知。但这种事嘛,互联网有记忆。

从泄露的源码里扒出了不少有趣的东西:

  • 103 个 feature flag(功能开关),包括 BUDDY(一个电子宠物功能)、KAIROS(后台守护进程)、VOICE_MODE(语音模式)
  • Undercover Mode——让 Anthropic 员工往开源项目提交代码时隐藏公司身份的系统
  • 完整的多 Agent 协调系统、内部 prompt 模板、工具定义

━━━━━━━━━━━━━━━━

📝 Source Map 是个啥

不搞前端的同学可能对 source map 没什么概念,简单解释一下。

现代 JavaScript 项目在发布前都会做一件事:把源码打包压缩。原本几千个文件、好几万行、带着清晰变量名的代码,会被压缩成一两个巨大的、变量名全变成 a、b、c 的文件。这样做一是为了减小体积,二是让代码不那么容易被人读懂。

但压缩后的代码出了 bug 怎么调试?总不能对着一行 50 万字符的代码找问题吧。这时候就需要 source map——一张对照表,记录着”压缩后的第 X 行对应原始代码的第 Y 个文件第 Z 行”。调试时浏览器或 IDE 用这张表把压缩代码还原成原始源码。

有个关键细节:source map 的 sourcesContent 字段里,直接保存了所有原始源文件的完整内容。拿到 .map 文件,就等于拿到了全部源码。

所以这玩意儿正常是绝对不该出现在发布包里的。Anthropic 这次就是在发布 @anthropic-ai/claude-code 2.1.88 版本时,把 cli.js.map 这个 59.8 MB 的大家伙一起打包发到了 npm 上。

━━━━━━━━━━━━━━━━

🛠️ 动手提取源码

搞明白原理之后,提取源码其实非常简单,总共就四步:

第一步,从 npm 下载发布包:

npm pack @anthropic-ai/claude-code@2.1.88

第二步,解压:

tar -xzf anthropic-ai-claude-code-2.1.88.tgzcd package

第三步,创建提取脚本。新建一个 extract-sourcemap.mjs 文件,从 sorrycc(陈成,Umi.js 作者)写的 gist 复制代码:https://gist.github.com/sorrycc/ec2968c6696f3cba361e3f6c9826e927

脚本干的事情很简单:读 .map 文件 → 遍历 sourcesContent → 跳过 node_modules → 按原始路径把每个源文件写到磁盘上。30 来行代码。

第四步,运行脚本:

node extract-sourcemap.mjs cli.js.map ./extracted-src

跑完之后,extracted-src 文件夹里就是 Claude Code 的完整源码了。

(Anthropic 已经从 npm 移除了这个版本,现在去下可能下不到了。GitHub 上镜像一搜一大把,找不到的可以公众号后台私信”源码”获取。)

━━━━━━━━━━━━━━━━

🔧 拿到源码之后:能看,但跑不起来

有人会问:拿到源码了,是不是直接就能跑?

答案是不能。

打个比方:你拿到的是一家米其林餐厅的全部菜谱手稿——每道菜怎么切、怎么炒、放多少盐,全都写在上面。但你只有手稿,没有厨房,没有食材,手稿上连”先做哪道菜”都没写。

具体来说,提取出的源码缺了这些东西:

缺什么
说人话
package.json
不知道要安装哪 90 多个依赖
tsconfig.json
编译器不知道怎么读这些代码
启动入口
1900 个文件不知道先跑哪个
7 个私有模块
有几味原料市面上买不到——Anthropic 内部的 @ant/* 包
MACRO 注入
版本号、构建时间这些运行时信息缺失

要让它跑起来,大概需要做 6 步:

  1. 装 Bun
    ——Claude Code 是用 Bun 写的,不是 Node.js,用 Node 跑第一行就报错
  2. 补 package.json
    ——扫描全部源文件,提取所有 import 的外部包名,写成依赖清单
  3. 补 tsconfig.json
    ——配置 TypeScript 编译选项和路径别名
  4. 给 7 个缺失的包做替身
    ——源码引用了 7 个在 npm 上根本找不到的包,其中 4 个是 Anthropic 内部没有开源的私有模块(@ant/* 开头的),另外 3 个虽然代码已经在源码里了,但引用方式是按包名引的,系统找不到。解决思路就是”绕过去”:给每个缺失的包造一个同名的替身,让程序加载时不崩溃就行
  5. 注入 MACRO + 写启动入口
    ——往全局变量里塞版本号等默认值,创建一个 5 行的启动文件
  6. bun install && bun run dev
    ——装依赖,跑起来

关于第 1 步。有人会问:前面提取源码用的明明是 node 命令,怎么跑源码又要用 Bun?

这俩是不同的 JavaScript 运行环境,关系类似于 Chrome 和 Firefox——都能跑 JS,但各有各的独家 API。提取脚本就是个普通的 Node.js 小脚本,用 node 跑没问题。但 Claude Code 的源码里大量使用了 Bun 独有的功能,比如 Bun.file()、Bun.spawn(),还有一个叫 bun:bundle 的内置模块——这些东西 Node.js 压根不认识,所以必须用 Bun 来跑。

再说第 4 步。那 4 个 Anthropic 内部模块(Computer Use 桌面控制、Chrome 浏览器集成等)在核心流程中并不是必需的。它们都躲在 feature() 这个功能开关后面——在非编译模式下,所有开关都返回 false,所以这些高级功能压根不会被执行。替身只需要”存在”就行,不需要真的能用。程序加载时看到这个包名有东西就不会崩,至于里面是不是空的,它不在乎。

如果不想自己折腾,GitHub 上已经有好几个现成的可运行仓库了(搜 claude-code-rev 或 start-claude-code),clone 下来直接跑。

想魔改的话,方向也很多:改 feature flag 打开隐藏功能、添加自定义工具、替换 API 端点接入自己的模型。

━━━━━━━━━━━━━━━━

💡 Anthropic 的回应:出了事故,反而要加速

这件事最让我觉得有意思的,不是泄露本身,而是 Anthropic 的回应态度。

Claude Code 之父 Boris Cherny 公开表示:这次泄露是人工失误导致的,部署流程中有若干手动步骤,其中一个执行错误,源码就跟着发布包出去了。团队已经上线了一些改进措施,正在继续加更多的合理性校验。

关键来了——他说团队的方向是加快流程,而不是增加更多手续。具体做法是提升自动化程度,并且用 Claude 来检查发布结果。

这个思路挺反直觉的。

大多数公司遇到这种事故,本能反应是什么?加审批、加 checklist、加人工复核。出了一次事故加一层锁,出两次事故加两层锁。结果流程越来越重,发布越来越慢,最后大家开始想办法绕过流程——然后又出事故,形成恶性循环。

Anthropic 的思路正好相反:人会犯错,那就减少人的参与;靠人眼校验容易漏,那就让 AI 来检查。不是出了事就加锁减速,而是让机器跑得更快、更自动、更靠谱。

这跟 DevOps 圈的一个经典理念一脉相承:系统出了 bug,解决方案不是减少部署频率,而是更频繁地部署 + 更快地回滚。部署越频繁,每次变更越小,出问题越容易定位,回滚越快风险越低。

对我们普通开发者来说,这个思路也值得借鉴。下次项目出了事故,开复盘会的时候,与其讨论”要不要加一个审批人”,不如先想想”能不能把出错的那个手动环节自动化掉”。加人是线性成本,加自动化是一次性成本。

用他们自己的 AI 产品来检查自己的发布结果,这也算是一种另类的”吃自己的狗粮”了。

━━━━━━━━━━━━━━━━

🎤 尾声

整件事最大的讽刺可能是:Anthropic 一直在强调 AI Safety,结果自己的代码安全翻车了。不过话说回来,这种发布时手滑带上了不该带的文件的事故,在工程界真不算罕见,只不过这次影响面大了点。

对于 Claude Code 的用户来说,源码泄露其实不影响正常使用。但对于想深入了解 AI 编程工具内部原理的开发者来说,这 51 万行 TypeScript 代码,确实是份绝佳的学习材料。

好了,写完这篇发现已经快十二点了。就酱。

📌 你觉得 Anthropic “出事故反而加速”的思路靠谱吗?你们团队遇到线上事故一般怎么处理?评论区聊聊。

#ClaudeCode#Anthropic#源码泄露#