无尘阁日记

无尘阁日记

让 AI 审代码安全,最怕它瞎编漏洞。Cloudflare 这个技能强制"换个人来反驳"(6.9 万星)
silcano

github监控器 · 2026-11-10 · 约 5402 字 · cloudflare/security-audit-skill

 

你用 AI 审过代码吗?它一般会给你一份看起来很专业的报告,里面有一半是"可能存在"。你真去验,大半不成立。

Cloudflare 这个技能的解法很硬:找漏洞的和验证漏洞的不能是同一个 agent。每个候选都要交给一个全新的验证者,任务是想办法反驳它。

6.9 万星,日均涨 476,MIT。它是 Cloudflare 内部漏洞挖掘 harness 的种子,这篇文章把六阶段流程、安装命令、三种裁决的区别、两个校验器全拆开讲。

一、先说结论:AI 审代码的两个病,它各有一个药

病一:幻觉。 模型会"看出"一个不存在的漏洞,然后编出一条像模像样的利用链。

病二:覆盖率造假。 它审了三个文件就宣布"全面审计完成",剩下两百个文件它没提,你也不知道它没提。

这两个病的根源是同一个:你只有一个 agent,它既当运动员又当裁判。

这个技能的做法是把角色拆开——发现的人不许验证,验证的人不知道是谁发现的。

README 里有一句设计原则,直接就是冲着这个来的:

"Adversarial validation. The agent that checks a finding is never the agent that found it."

security-audit 数据卡

二、它是什么:一个 Cloudflare 内部系统的种子

README 开头讲了它的来历,这段值得看:

"This is the skill that seeded Cloudflare's vulnerability discovery harness... The harness grew into a multi-stage, fleet-wide system; this skill is the single-repo starting point it evolved from."

翻译一下:Cloudflare 内部有一套跑在整个公司代码库上的漏洞挖掘系统,这个技能是它最早的那颗种子。

这句话的信息量在于:它不是"论文里的方法",而是在真实环境里被撑大过的东西,然后砍回到单仓库可用的规模放出来。

配套还有一篇官方博客《Build your own vulnerability harness》,讲整套系统怎么演进。技能本身是能直接跑的那部分。

三、六阶段:整个流程长什么样

这是核心。六个阶段,每个阶段有明确产物,上一个阶段的产物是下一个阶段的输入:


阶段
干什么
产物
1. 侦察
画出架构、信任边界、输入面、既有证据、确定性覆盖范围
architecture.md / coverage-ledger.json
2. 覆盖驱动的狩猎
从台账里分派相互隔离的猎手,记录检查项,用"覆盖批评者"找缺口
台账更新 + 检查记录
3. 候选验证
每个候选交给一个全新的验证者,任务是证伪
候选的去留
4. 结构化输出
把 confirmed / needs_validation / rejected 写进文件,并按 schema 校验
findings.json
5. 独立记录核验
全新 agent 复核最终源码断言;重大替换再找第二个验证者
核验后的记录
6. 目标中立的报告
从核验过的记录和覆盖台账推导出三份报告
REPORT.md / FINDINGS-DETAIL.md / NEEDS-VALIDATION.md

第一阶段那个 coverage-ledger 是整套设计的支点。

它不是一个清单,是一个账本:哪些地方查了、查了什么、结论是什么、哪里还没查。后面所有阶段都对着这本账干活。

这就直接治了"覆盖率造假"——你没法宣布审完了,因为账本上有未覆盖项。

README 里的流程图

四、为什么"证伪"比"确认"重要

第三阶段那句 "a fresh verifier that tries to disprove it" 是整套设计里最反直觉的地方。

一般流程是:找到候选 → 再确认一遍 → 报告。

问题是"再确认一遍"的心理预设是"它大概是对的",agent 会顺着找证据,这就是确认偏误。

它改成"想办法证明它是错的"。这个转向带来两个效果:

  1. 真漏洞经得起证伪。 有源码痕迹、有可观测结果的,反驳不掉;
  2. 假漏洞一碰就碎。 编出来的利用链,找不到源码支撑,当场掉。

这也是为什么三种裁决里,rejected 是一等公民——它不是"没找到",是"被证伪了",这个记录本身有价值。

五、三种裁决:别混着看

README 对三种裁决的定义很精确,我按原意翻:


裁决
定义
有什么
没有什么
confirmed
完整的源码追踪 + 有边界的观测结果
源码链、可复现结果、严重度
推测
needs_validation
有一个精确的未解决事实
那条卡住的具体问题
严重度(不许给)
rejected
候选被证伪的记录
为什么被推翻
任何严重度

注意 needs_validation 不许带严重度这条规定。

这是个很聪明的约束。因为一旦你给未验证的东西打了"高危",它就会在报告里被当成高危处理,"未验证"这个前提就被丢了。

同理,设计原则里有这么一条:

"Defense-in-depth gaps are not vulnerabilities. If Layer A prevents the attack, the absence of Layer B is a hardening note."

翻成人话:A 层已经挡住了,B 层没有不算漏洞,那叫加固建议。

这条能把报告里的水分挤掉一大半。

六、装:一条 npx,两分钟

用 Skills CLI 装,官方给的是这一条:

npx skills add https://github.com/cloudflare/security-audit-skill \
--skill security-audit

要装成用户级(所有项目都能用),加 --global:

npx skills add https://github.com/cloudflare/security-audit-skill \
--skill security-audit \
--global

其它选项(选哪个 agent、非交互模式)看 npx skills --help。

装完确认一下:技能目录里应该有一堆 .md 和两个 .cjs。如果只有 SKILL.md,说明没装全,攻击类清单那些文件是分开的。

七、怎么用:三句话,它自己认

在你要审的代码库里(或者把 agent 指向那个目录)启动,然后直接说人话:

security audit this codebase

或者:

find security vulnerabilities in ./src

或者指定输出目录:

do a security review, output to ~/audits/my-project

触发是自动的——请求里出现 security audit、find vulnerabilities、pen-test the code 这类词,技能就激活。

两种模式要分清,这是 README 明确区分的:


你说的话
模式
行为
审这个代码库 / 做渗透测试
全量审计
跑完整六阶段
"这个函数有注入风险吗"
指导模式
只回答,不出报告产物
要报告产物
全量审计
显式要求才出三份报告

输出目录的默认值记一下:~/security-audit-skill/<repo-name>/run-<N>。

那个 run-N 是自增的——说明它天生预期你会跑很多次,下一节讲为什么。

还有一条很容易被忽略但很重要:

"The workflow writes inside the target repository only when you explicitly select a directory that version control ignores."

意思是默认不往你的仓库里写东西。要写进去,你得主动指定一个被 .gitignore 忽略的目录。这是防止污染工作区。

README 里的产物结构

八、跑多次不是缺陷,是设计

这是我认为整个项目最诚实的一句话:

"In our test runs, a single run found roughly half of the vulnerabilities that repeated runs found in total."

跑一次只找到一半。 这是他们自己的测试数据。

所以 README 里专门有一节讲"多次运行是累加的":

后续运行会读之前的台账和发现,用来做三件事:

  1. 针对缺口下手,不重复已覆盖的地方;
  2. 重新验证改动过的源码(源变了,旧结论可能失效);
  3. 把当前源码的证据结转过来——但不会把过期的、未解决的工作算成已覆盖。

第三条是关键。很多工具"接着上次跑"就是把旧结论当既成事实,它明确不这么干。

实务建议:重要项目至少跑三轮。 第一轮摸面,第二轮补缺口,第三轮交叉验证。

九、两个校验器:它是真的在卡格式

这个技能带两个零依赖的 Node 脚本,用来自动卡你的输出格式:


脚本
校验什么
什么时候跑
validate-coverage-ledger.cjs
coverage-ledger.json
建完台账后,以及后续每次台账更新后
validate-findings.cjs
findings.json
第四阶段,以及第五阶段每次替换后

"零依赖"意味着不用 npm install,有 Node 就能跑。这点挺重要,不然一个审计技能还得先装一堆包。

手动跑长这样:

node validate-coverage-ledger.cjs <path-to-coverage-ledger.json>
node validate-findings.cjs <path-to-findings.json>

它连测试都一起放出来了(*.test.cjs),其中 validate-findings.test.cjs 还带生产者兼容性 fixture 检查——就是确保"校验器和产出器不会各说各话"。

这个细节说明一件事:它是奔着"能被别人接着做"去写的,不是一次性的 demo。

十、硬性要求:没有沙箱,它就不执行目标代码

这一节请务必读完,因为它关系到你会不会把自己机器搞坏。

README 的 Requirements 里第三条写得非常具体:需要一个操作系统级沙箱,用来跑目标代码的构建、测试、进程、浏览器、模拟器、fuzzer、fixture。

这个沙箱必须做到四件事:


要求
具体含义
断外网
禁掉对外网络,防止被审计的代码往外发东西
净化环境
用白名单环境变量,不继承你的 shell
资源限额
限制 CPU/内存/进程数,防止跑飞
只写临时区
只允许写指定的 scratch 路径

然后是最关键的一句:

"Without these controls, the workflow keeps the lead as needs_validation instead of executing target code."

没有沙箱,它不会跑目标代码,直接把线索挂在 needs_validation。

这个降级设计我很认同——宁可少一条结论,不赌一次执行。

实务上:本机用容器或虚拟机做隔离,别在主力机的裸环境上跑陌生代码的构建。

十一、五条设计原则,每条都能省你一次误报

README 末尾列了五条,我逐条加一句人话注解:


原则
原文要点
人话
只确认确凿的边界突破
有源码支撑但没打穿的线索,保留为 needs_validation
差一步就是差一步,不许升格
对抗式验证
验证者永远不是发现者
换人反驳,不许自证
严重度必须有影响
可能性 × 影响,不是清单偏离度
不对着 checklist 打分
纵深防御缺口不是漏洞
A 层挡住了,B 层缺失只是加固建议
别把"没有第二道锁"报成漏洞
多次运行提升覆盖
单次约找到一半
重要项目跑三轮

第三条值得多说一句。"偏离清单"是很多安全扫描器的通病——看到没开某个 header 就报中危,但它不给出一条能走通的攻击路径。

这个技能要求"严重度必须有影响",等于强制你写出攻击怎么走。写不出,就降级。

十二、谁该用,边界在哪


你是谁
建议
有代码库要定期做安全体检
值得装,流程比结果更有价值
做安全研究的
重点看它的台账设计和对抗验证
要给甲方出审计报告
可以用,但 confirmed 项仍需人工复核
没沙箱环境
能用,但会大量停在 needs_validation
想替代专业渗透测试
不行,它是辅助不是替代

最后一条必须说清楚。这个技能产出的是"候选 + 证据链",不是"审计结论"。

它的价值在于:把一个团队要花两周的初筛,压缩到几小时,并且把"哪里没查"也一起交给你。

至于最后那一句"这个到底算不算漏洞",还是得人来签。

十三、版本与地址


项目
内容
仓库
github.com/cloudflare/security-audit-skill
许可
MIT
语言
JavaScript
安装
npx skills add ... --skill security-audit
依赖
Node.js(校验器零依赖)
建仓
2026-06-18
当前星数
约 6.96 万
联系
security-ai-research@cloudflare.com
形态: coding-agent 技能(六阶段安全审计)
许可: MIT
安装: npx skills add https://github.com/cloudflare/security-audit-skill --skill security-audit
触发: security audit this codebase
产物: architecture.md / coverage-ledger.json / findings.json / REPORT.md
校验: node validate-findings.cjs + validate-coverage-ledger.cjs
前提: 有沙箱,否则不执行目标代码

最后一句:AI 审代码这件事,最大的问题从来不是"不够聪明",而是它太愿意给你一个答案。这个技能做的所有设计——分离角色、强制证伪、卡死格式、留台账——本质上都在干一件事:让"我不知道"变成一个可以输出的结果。

 

关于作者 · 江天(楠哥)
AI 实战导师 / 企业 AI 落地顾问 / 智能体工程师,17 年跨界、15,000+ 小时 AI 实操、20+ 套已交付工作流。