Bun 还原 claude code 源码泄露全过程为什么一个 `.map` 文件泄露等同于泄露?
最近 claude code 源码被泄露,大家应该人手一份了吧。
本文从技术角度还原 claude code 源码泄露过程,解答为什么仅一个 .map 文件泄露几乎等同于源码泄露。
代码复原
pnpm init 生成如下目录结构:
❯ tree . claude-code-leak-incident-reconstruction-using-bun├── LICENSE├── README.md├── cli.ts└── package.json
cli.ts:
#!/usr/bin/env node// (c) Anthropic PBC. All rights reserved. Use is subject to the Legal Agreements outlined here: https://code.claude.com/docs/en/legal-and-compliance.// Version: 2.1.89// Want to see the unminified source? We're hiring!// https://job-boards.greenhouse.io/anthropic/jobs/4816199008function greet(name: string) { // 第1行// 第2行(空行)if (!name) { // 第3行(4空格缩进)return "Hello stranger"; // 第4行(8空格缩进) } // 第5行(4空格缩进)// 第6行(空行)return `Hello ${name}`; // 第7行(4空格缩进)} // 第8行// 第9行(空行)// 文件结束 // 第10行console.log(greet('Claude Code.'))
可以看到我们故意加了很多空格和注释就是为了试试看,仅有一个 .map 是否能完完全全字符级别精确复原代码。
执行构建:bun build cli.ts --minify --outfile=cli.js --sourcemap=linked
生成两个文件,目前目录结构如下:
❯ tree . claude-code-leak-incident-reconstruction-using-bun├── LICENSE├── README.md├── cli.js # bun 构建生成├── cli.js.map # bun 构建生成├── cli.ts└── package.json
我们主要看看这个导致 Claude Code 泄露的“罪魁祸首” cli.js.map:
{"version": 3, "sources": ["cli.ts"], "sourcesContent": ["#!/usr/bin/env node\r\n// (c) Anthropic PBC. All rights reserved. Use is subject to the Legal Agreements outlined here: https://code.claude.com/docs/en/legal-and-compliance.\r\n\r\n// Version: 2.1.89\r\n\r\n// Want to see the unminified source? We're hiring!\r\n// https://job-boards.greenhouse.io/anthropic/jobs/4816199008\r\nfunction greet(name: string) { // 第1行\r\n // 第2行(空行)\r\n if (!name) { // 第3行(4空格缩进)\r\n return \"Hello stranger\"; // 第4行(8空格缩进)\r\n } // 第5行(4空格缩进)\r\n // 第6行(空行)\r\n return `Hello ${name}`; // 第7行(4空格缩进)\r\n} // 第8行\r\n // 第9行(空行)\r\n// 文件结束 // 第10行\r\n\r\nconsole.log(greet('Claude Code.'))" ], "mappings": ";AAOA,SAAS,CAAK,CAAC,EAAc,CAEzB,GAAI,CAAC,EACD,MAAO,iBAGX,MAAO,SAAS,IAKpB,QAAQ,IAAI,EAAM,cAAc,CAAC", "debugId": "0CD11855101BFF5E64756E2164756E21", "names": []}
可以看到其实就是一个 json 文件,里面的 sourcesContent 包含了完整的源码!
sourcesContent 内容:
#!/usr/bin/env node// (c) Anthropic PBC. All rights reserved. Use is subject to the Legal Agreements outlined here: https://code.claude.com/docs/en/legal-and-compliance.// Version: 2.1.89// Want to see the unminified source? We're hiring!// https://job-boards.greenhouse.io/anthropic/jobs/4816199008function greet(name: string) { // 第1行// 第2行(空行)if (!name) { // 第3行(4空格缩进)return "Hello stranger"; // 第4行(8空格缩进) } // 第5行(4空格缩进)// 第6行(空行)return `Hello ${name}`; // 第7行(4空格缩进)} // 第8行// 第9行(空行)// 文件结束 // 第10行console.log(greet('Claude Code.'))
可以看到 shebang、注释、TS 类型(string)、空格、空行一个不少。对比下字符数:
❯ wc -m sourcesContent.ts867 sourcesContent.ts❯ wc -m cli.ts867 cli.ts
一模一样!这下大家知道了为何 sourcemap 文件泄露等同于源码泄露。
构建参数 –sourcemap=inline 会泄露源码吗?
结论先行,一样会!
- ❯ bun build cli.ts --minify --outfile=cli.js --sourcemap=linked+ ❯ bun build cli.ts --minify --outfile=cli.js --sourcemap=inline
function c(b){if(!b)return"Hello stranger";return`Hello ${b}`}console.log(c("Claude Code."));//# debugId=0CD11855101BFF5E64756E2164756E21- //# sourceMappingURL=cli.js.map+ //# sourceMappingURL=data:application/json;base64,ewogICJ2...fQ==
会生成一段类似乱码:data:application/json;base64,ewogICJ2ZXJ... 但仔细一看其实是 base64。我们可以通过 base64 cli 还原 ❯ echo 'ewogICJ2ZXJzaW9...==' | base64 -d:
❯ echo 'ewogICJ2ZXJzaW9uIjogMywKICAi...ogW10KfQ==' | base64 -d
输出
{"version": 3, "sources": ["cli.ts"], "sourcesContent": ["#!/usr/bin/env node\r\n// (c) Anthropic PBC. All rights reserved. Use is subject to the Legal Agreements outlined here: https://code.claude.com/docs/en/legal-and-compliance.\r\n\r\n// Version: 2.1.89\r\n\r\n// Want to see the unminified source? We're hiring!\r\n// https://job-boards.greenhouse.io/anthropic/jobs/4816199008\r\nfunction greet(name: string) { // 第1行\r\n // 第2行(空行)\r\n if (!name) { // 第3行(4空格缩进)\r\n return \"Hello stranger\"; // 第4行(8空格缩进)\r\n } // 第5行(4空格缩进)\r\n // 第6行(空行)\r\n return `Hello ${name}`; // 第7行(4空格缩进)\r\n} // 第8行\r\n // 第9行(空行)\r\n// 文件结束 // 第10行\r\n\r\nconsole.log(greet('Claude Code.'))" ], "mappings": ";AAOA,SAAS,CAAK,CAAC,EAAc,CAEzB,GAAI,CAAC,EACD,MAAO,iBAGX,MAAO,SAAS,IAKpB,QAAQ,IAAI,EAAM,cAAc,CAAC", "debugId": "0CD11855101BFF5E64756E2164756E21", "names": []}
姐妹们,看到没有 inline 其实就是将整个 map json 文件 base64 了,解码后里面赫然存在 sourcesContent,其内容和 cli.ts 源码一模一样!
附录
本文还原 Claude Code 泄露过程的所有代码已经放在
legend80s/claude-code-leak-incident-reconstruction-using-bun
大家安装好 bun 后执行 ❯ bun build cli.ts --minify --outfile=cli.js --sourcemap=linked 或直接运行 bun run build。
#claudecode #源码泄露 #claudecode源码泄露 #bun #anthropic #ai #agent #ClaudeCode #Claude编程助手#opencode #前端转AI #Agent
夜雨聆风