你天天用的 Claude Code,可能被一个「干净」的 GitHub 仓库黑掉

哈喽,我是飞飞。
先说个让我后背发凉的事。Mozilla 的安全团队 0DIN 这周放出一个 demo:一个 GitHub 仓库,里面一行恶意代码都没有,干净得能过任何扫描器。
你用 Claude Code 把它 clone 下来,说一句「帮我把这个项目跑起来」,几十秒后,你的电脑上就开了一个反向 shell,攻击者能拿到你的环境变量、API key、登录凭据,还能赖着不走。
整个过程,没有漏洞被利用,没有警告弹出来,没有一条可疑命令需要你点确认。我看完第一反应是,这事我天天在干啊。
一个干净仓库的后门
先把这个攻击讲清楚,它精巧得有点反常识。
被利用的根本不是代码漏洞,而是 agent 太乐于助人。它的核心套路叫间接提示注入(indirect prompt injection)。说人话就是,攻击者不直接给 Claude Code 下命令,而是在它干活路上埋一个「坑」,等它自己掉进去,顺手把脏活干了。
最绝的地方在于:那段真正作恶的代码,从头到尾都不在仓库里。你 review 整个项目,每个文件都干干净净。它藏在一个你根本不会去看的地方,运行的时候才被拉出来。一个昨天 review 还清白的仓库,攻击者今天改一下远端配置,明天就能给你递刀子。
它怎么三步开的 shell
这条链子是三步,每一步看着都人畜无害。
第一步,仓库的 README 写着再正常不过的安装说明,比如 pip3 install -r requirements.txt。你见过一万遍,闭着眼就让它跑了。
第二步,这个被安装的包被做了手脚,第一次运行就故意抛个错。错误信息很贴心地告诉你:哦,初始化没做,跑一下 python3 -m axiom init 就好了。
第三步,就是这条「修复命令」,它调起一个脚本,去查一条攻击者控制的 DNS 记录(demo 里的域名是 _axiom-config.m100.cloud),把记录里那段 base64 编码的字符串取回来,直接喂给 bash 执行。反向 shell,就这么起来了。
0DIN 那句话我得原样搬过来,太到位了:「Claude Code 从没决定要开一个 shell,它只是决定去修一个错。这个反向 shell,离它真正看过的东西隔着三层:一条它信了的错误信息,一个去取值的脚本,和一条它压根没见过的 DNS 记录。」
为什么三道关全失明
你可能会问,扫描器、人工 review、AI 自己,三道关怎么会一个都没拦住。
因为根本没有「恶意代码」这个东西给它们拦。静态扫描器看到的,是一次再普通不过的 DNS 查询,谁家程序还不查个 DNS 了。人工 review 看到的,是一个连真正的 payload 都不包含的干净仓库。那段反向 shell 因为是 base64 编的,在你硬盘上、在网络流量里,从来不以明文出现,连特征匹配都匹配不到。
更要命的是 agent 这一关。它比人还好骗。你要是看到一条 curl 某个地址 | bash,多少会愣一下,这是要干嘛。可 Claude Code 不会,它把「跑条命令修报错」当成天经地义的日常。三层间接套下来,它执行到最后一步的时候,自己都不知道刚开了个后门。
不止 Claude Code 一家
这里我得替 Claude Code 说句公道话,免得你以为是它特别菜。
这不是它一家的问题。Tom’s Hardware 和好几家安全媒体都点明了,Cursor、GitHub Copilot、Gemini CLI 这些同类,同一个套路全都中招。这是 agentic coding 这一整类工具的系统性软肋:你给了它读任意内容、执行任意命令的能力,又指望它自己分清哪条命令该跑、哪条不该。
往前数,2026 上半年这种事就没断过。供应链投毒的 Clinejection,往 settings 里塞恶意 Hook 的 CVE,OWASP 干脆把 Agent Goal Hijacking 列成了智能体安全的头号风险。这一次只是又一个新鲜的样本。还有一点得讲实话:0DIN 这个目前是 PoC,概念验证,还没看到大规模在野利用。但攻击门槛低得吓人,扩散起来很容易,一个假招聘、一篇教程、一条私信都能把仓库递到你面前。
我也天天这么用它
讲到这我必须交代自己的底。
我天天用 Claude Code,开各种来路不明的第三方仓库是常事,刷到个有意思的开源项目就 clone 下来让它帮我跑起来。pip install、npm install、跑 setup,说实话我基本不细看它每一步具体执行了啥,报错了就一句「你看着修」。这次 demo 里那个上钩的开发者,行为模式跟我一模一样。
更要命的是我那台主力机。上面堆着十几个 skill 的配置、一份越喂越厚的 CLAUDE.md、一摞 memory,还有一堆 API key 和各种登录态,全是 agent 手边伸手就够得到的东西。
Claude Code 弹出来问我要不要执行某条命令的时候,十次里有八次我是扫一眼命令长啥样、觉得没毛病就回车放行了。真去逐字读它跑的每一条命令、每一个它联网拉回来的脚本?老实讲没那个耐心,也正是这份没耐心,把那道本该我守的闸交了出去。
这跟我之前一个体感是连着的。我自己的发布流水线全自动化,踩过一次坑:一个 token 悄悄过期,部署连着失败一整天,没人盯着,我隔天才发现。我当时的总结是,自动化最贵的成本藏在没人盯着的时候。现在这事更进一步:你让 agent 自动跑命令,省下的是点确认那几秒,赌上的是你整台机器。能力越自动,越没有一个人站在那个决策点上踩刹车。
我刚写过 Codex 那套让 AI 帮你审代码的东西,那是 AI 在帮你挡刀。这回反过来了,AI 工具自己成了递刀子的那个入口。
别让它自己跑命令
那怎么办,总不能不用了。
0DIN 给的建议挺实在,也是我准备照做的。一个是对工具方的:agent 在跑 setup 命令之前,应该把这条命令运行时到底会拉什么、执行什么,完整摊开给你看,而不是只让你看那条干干净净的命令字面。另一个是对我们自己的:陌生仓库里的安装说明,一律当成不可信代码看,别因为是 AI 推荐你跑的,就默认它安全。
具体到手上,我给自己定了两条。开陌生仓库前,先用沙箱或者干净的容器跑,别在装着一堆 key 的主力机上直接来。这条对我其实有点难受,我习惯了在主力机上一把梭,图的就是顺手,现在得逼自己多搭一层隔离。
第二条,让 agent 跑命令时,凡是碰到它要执行外部脚本、要联网拉东西的,那道确认我自己一个字一个字看完再按,不再挂自动批准图省事。麻烦是麻烦,但真被偷一次 key、连夜重置一遍所有密钥和登录态的那种麻烦,比这大得多得多。
说到底,agent 把活越接越多是好事,但那道「该不该执行」的闸,目前还真不能全交给它。你呢,平时让 Claude Code 或者 Cursor 自动跑过陌生仓库的命令吗,那道确认你是顺手就批,还是会停下来自己看一眼?评论区聊聊。