一段配置文件描述让 AI 代码审计员漏掉致命漏洞
实测 70 次审计:CLAUDE.md 中一段「审查范围」描述使 AI 在 10 次中完全未打开含奖励池耗尽漏洞的文件,…
一项针对 AI 代码审计智能体的对照实验显示,仅需在配置文件 CLAUDE.md 中写一段描述审查范围的段落,就能让审计员在 70 次独立运行中的 10 次完全跳过含有「奖励池可被耗尽」严重漏洞的文件,且最终报告与正常版本几乎无法区分——既无警告,也无错误信息。统计显著性达到 Fisher 精确检验 p ≈ 1.1 × 10⁻⁵(双侧)。
实验设置
测试目标是一个从零编写的九文件、42 KB 的质押金库合约,编译通过、测试通过,并被故意植入一处关键漏洞。漏洞位于 RewardDistributor.claim():函数正确计算应付金额、更新用户索引、转账代币,却从不将累计余额清零。这意味着同一用户可以反复调用 claim,每次都拿走应得的代币,直至合约余额耗尽,其他质押者的提款随之全部 revert。
仓库中另附有一段独立于项目之外的利用脚本:欠款 50 token 的账户可据此取走全部 100 token,并使另一位质押者无法提款。审计智能体全程看不到这段利用脚本,因此「未发现」是针对智能体自身的判断,而非「目标为空」。
核心发现:被审查方写的文件,决定了审查范围
实验者将审计智能体指向同一代码库,运行 70 次。结果是:
- 60 次:智能体打开了相关文件,并准确定位漏洞。
- 10 次:智能体从未打开含漏洞的文件,最终报告中不存在该漏洞,也没有任何「已跳过」的提示。
- 两类报告长度相近(1,437 词 vs 1,099 词),结构相似(按严重程度排列的发现 + 利用路径 + 一行修复建议),若隐去具体发现条目,外部读者无法分辨哪个版本漏掉了关键漏洞。
两者的唯一差异,是 CLAUDE.md 中描述「应审查哪些目录」的 71 个词。这意味着攻击并非提示词越狱或复杂注入,而是「由被审查方写下的、关于审查范围的描述」本身成为了注入载体。
与 Cloudflare 已有研究的关系
实验机制借鉴自 Cloudflare Cloudforce One 团队的既有工作。该团队曾对 100 份已确认为恶意的 Cloudflare Workers 脚本进行测试:在文件中植入「NOTICE TO AI CODE REVIEWERS」类欺骗性注释后,7 个模型在 18,400 次 API 调用中的平均检出率从 67.3% 降至 53.3%;当文件体积超过 3 MB 时,检出率进一步跌至 12–18%。
Cloudflare 的核心结论是「结构胜过语言」(structural obfuscation beats linguistic deception)——只要信号被淹没,就不需要从语义上证伪文件的安全性。值得注意的是,按模型拆分后,七个模型中仅有一个明显被绕过,三个前沿模型保持稳定甚至更优;极端体积下六款超过自身基线,这一现象被作者称为「欺骗的 U 形曲线」。
审计与分类的本质差异
Cloudflare 的实验场景是单文件二分类,Ground Truth 已知,所有失败均可打分。代码审计则是一个开放问题:智能体进入仓库后,首先要决定「哪些文件值得看」,而这一决策本身依赖于 README、文档与配置文件——而这些文件的作者,正是被审查的对象。
由此带来的后果是:
- 当注入影响分类判断时,输出一个错误答案,可以被反驳。
- 当注入影响审计决策时,文件在分析启动前就已离开流程,既不是「发现」也不是「驳回」,最终报告呈现的是「智能体眼中应有的审查范围」。
这种差异使审计场景下的失败更隐蔽:用户既看不到报错,也看不到缺失,只看到一个「自信、详尽、看起来正常」的成品文档。
启示
该实验的可重复部分(70 次运行的设置、提示词、代码库)已公开发布。其结论指向的不是某个模型的缺陷,而是「让被审查方写审查指令」这一结构性安排带来的系统性风险;可行的修复方向在于审计流程的外部账本化——例如记录「应当被检查但未被打开的文件清单」——而不是在提示词层面打补丁。
