51万行代码裸奔,木马闻着味来了
Anthropic因npm打包疏忽泄露Claude Code完整客户端源码,51万行未混淆TypeScript被大量复刻。Zscaler发现威胁组织借伪造GitHub仓库、SEO抢排名分发Vidar窃密木马。本文拆解完整攻击链,并讨论AI工具供应链安全的新暴露面。
安全圈最近流传一句半开玩笑的话:最好的漏洞情报,有时候不是别人攻进来的,而是厂商自己把门卸了。Anthropic 的 Claude Code 源码泄露事件,恰好把这句话演成了现实——一次打包疏忽,51.3万行未混淆的TypeScript代码裸奔上线,而最先赶到的不是研究者,是投递窃密木马的威胁组织。
核心判断先行:这次事件里,泄露本身造成的直接风险有限,真正的杀伤链发生在「围观泄露」的人群身上。攻击者卖的不是漏洞,是好奇心。
📦 一个59.8MB的疏忽
金句先放这儿:供应链的断点,往往不在惊天漏洞里,而在一次没勾掉的打包选项里。
先复盘泄露是怎么发生的。Anthropic 在发布 Claude Code 的npm包时,因疏忽意外嵌入了一个大小为59.8MB的JavaScript源码映射文件(source map)。这类文件的本职是把编译产物映射回源码,方便调试——但在发布包里带着它,等于把编译前的完整源码原样奉上。
这里值得把机制拆开讲清楚。前端工程在构建阶段通常用 esbuild、webpack 或 tsc 等工具把TypeScript打包压缩成运行时JavaScript,构建配置里一般有一个类似 sourcemap: true 的开关。开启后,工具会产出一个 .map 文件,其内部结构是标准的四段式:version(映射规范版本)、sources(原始文件路径列表)、mappings(编译产物与源码行列的对应关系,经Base64 VLQ编码)以及最致命的 sourcesContent——这个字段会把每个原始文件的完整源码文本直接内嵌在映射文件里。也就是说,只要一个 .map 文件进入发布产物,混淆和压缩就全部失效,攻击者甚至不需要还原映射关系,从JSON里抠出 sourcesContent 就能拿到全部源码。
那它是怎么进入npm包的?常见的失误路径有三条:构建工具的全局配置在发布构建时没有被关闭;打包脚本是「把整个 dist 目录复制进包体」而 .map 文件恰好生成在同一目录;或者 package.json 的 files 白名单用了宽泛的目录匹配而没排除 .map。59.8MB的体积也侧面印证了这是内嵌源码的完整映射——如果只含 mappings 不含 sourcesContent,文件会小一个数量级。这也是发布流水线审计的基准动作:npm pack --dry-run 列出待发布文件清单、检查是否含 .map,成本极低却最容易被跳过。
后果是:这款终端版AI代理工具的完整客户端源代码被公开泄露。泄露内容包括1906个文件、共计51.3万行未做混淆处理的TypeScript代码。Claude Code 可以直接在终端中执行编程任务,作为自主代理实现系统直接交互、大语言模型API调用管理、MCP集成以及持久化记忆等功能,这些能力的调度逻辑、权限与执行机制在这次泄露中一览无余。
值得注意的是,这次泄露是任何人都可以独立复核的公开事实:通过 npm view @anthropic-ai/claude-code 查看包的元数据与体积变化,用 npm pack 拉取对应版本的tarball并检索 .map 文件,即可确认映射文件的存在与内容。这也是本次事件与一般「匿名爆料」性质不同的地方——它不是需要信任链的情报,而是可验证的供应链事故。
代码很快被大量用户下载并上传至 GitHub,出现数千次复刻分叉(fork)。到这里,事件还是一场典型的「意外开源」——厂商尴尬,社区围观,技术上没有直接危害。
真正的转折在下一幕:有人开始利用这场泄露变现,而变现方式不是研究,是投毒。
🎣 恶意仓库的SEO生意经
金句:攻击者不再等用户犯错,他们主动站到用户搜索的第一行。
Zscaler 在报告中指出,此次源码泄露为威胁组织创造了可乘之机——专门盯上那些搜索Claude Code泄露内容的用户。
手法并不新鲜,但执行得很讲究。研究人员发现,一个由用户「idbzoomh」发布的恶意 GitHub 仓库,上传了伪造的泄露版本,并宣称该版本「解锁企业级功能」且无使用限制。这个钩子打得极准:源码泄露的消息传开后,大量用户想第一时间拿到所谓「完整版」,而「解锁企业级功能」直接命中了那部分想绕开付费墙的人。
更关键的一步是搜索引擎优化。该仓库针对搜索引擎做了专门优化,在谷歌搜索「leaked Claude Code」等关键词时,会出现在前列位置。攻击者预判了用户的搜索行为,提前在搜索结果里布好了陷阱——用户以为自己在找泄露的代码,实际上是在往木马的投递管道里走。
Zscaler 还发现了第二个代码完全相同的仓库,在分析期间其「下载ZIP」按钮处于失效状态。Zscaler 判断其由同一威胁组织运营,可能用于测试不同的投放传播策略。换句话说,这不像随手搭的钓饵,更像一次有运营节奏的投放活动。
⚠️ 拆开压缩包:Vidar加GhostSocks
金句:看懂一条投递链,比看十份泛泛的威胁报告更有用。
用户被诱导下载到的,是一个 7-Zip 压缩包,其中包含一个名为ClaudeCode_x64.exe的Rust语言可执行程序。
程序运行后,会释放投放通用窃密木马 Vidar,同时安装 GhostSocks 网络流量代理工具。两个载荷的分工很清晰:
| 载荷 | 类型 | 典型作用 |
|---|---|---|
| Vidar | 通用窃密木马 | 窃取浏览器凭据、会话、本地敏感数据 |
| GhostSocks | 网络流量代理 | 把受害者机器变成流量跳板 |
窃密木马负责拿数据,流量代理负责把这台机器接入黑产的基础设施。前者是即时变现,后者是可以反复出售的「资产」。一台被同时装上两者的机器,在地下市场的价值远不止一次窃密。
Zscaler 还监测到一个动态细节:该恶意压缩包会频繁更新,未来不排除被加入其他恶意载荷的可能。这意味着当前看到的Vidar加GhostSocks组合,可能只是第一阶段——攻击者保留了随时更换或叠加载荷的灵活性。
把完整攻击链串起来:
这条链上没有一个0day,没有一次漏洞利用。攻击的全部成本,是一个仓库、一次SEO投放和一堆现成的黑产工具——而撬动的入口,是厂商的打包疏忽加上用户的好奇心。
💡 泄露的代码不致命,致命的是围观者
金句:真正需要修补的漏洞,在发布流水线里,也在每一个搜索框后面。
事后看,这次泄露对 Anthropic 的直接影响更多是工程和安全层面:调度逻辑、权限与执行机制、隐藏功能以及多项安全相关核心实现被完整公开,等于把自家客户端的实现细节摊在了台面上。对防御方来说,这意味着攻击者研究其客户端行为、寻找逻辑弱点的门槛被大幅拉低。
但更值得整个行业记住的,是攻击者展现出的「借势」能力:厂商的一次失误,社区的数千次分叉,用户的搜索热情,每一环都被单独拿出来变成了攻击资源。攻击链的起点甚至不在受害者的机器上,而在谷歌的搜索结果页上。
对厂商,教训可以落成一条可执行的检查清单:构建配置里调试用的 sourcemap 开关与发布构建严格分离;CI在发布前强制执行 npm pack --dry-run 并断言产物中不存在 .map;源码映射文件应当和密钥、凭据一样,被列入发布前的强制检查项。AI代理工具这类深度接触终端系统的产品,客户端实现本身就是敏感资产,打包策略要按这个标准来定。
对开发者用户,教训更简单:任何声称「解锁企业级功能」「无使用限制」的泄露版本,本质都是在用你的本机凭据去交换一个不存在的福利。尤其是AI编程代理这类工具,一旦运行在开发机上,窃密木马拿到的就不只是个人数据,还可能是生产环境的凭据链。核实一个仓库是否为官方发布,只需要比对npm官方页面上的维护者和仓库链接——成本一分钟,省下的可能是一整条凭据链。
对一个把代码和工具当资产的行业来说,最大的暴露面从来不是防火墙,是人心。源码泄露会过去,搜索框后面的陷阱不会。
结语
从59.8MB的映射文件,到51.3万行裸奔的TypeScript,再到SEO排第一的恶意仓库和 Vidar 的投递链,这次事件完整演示了AI时代的供应链风险如何被逐级放大。可以预判的是,随着AI工具的发版节奏越来越快,类似的「打包疏忽+热点投毒」组合还会出现。厂商该做的,是把发布流水线当成攻击面来治理;用户该做的,是对每一个「泄露版」保持本能的怀疑。热点会冷却,木马的更新不会——Zscaler 已经提醒,那个压缩包还在频繁更新。