Cloudflare 把内部漏洞挖掘系统的"单仓库起点"开源了:security-audit-skill,一个让 Coding Agent 对代码库做结构化安全审计的 Skill。它不是一个模型,也不是一个扫描器,而是一套写给 Agent 的编排协议------这恰恰是最值得看的部分。
它是怎么干活的
整个审计分六个阶段:
- 侦察 :让 Agent 先画地图------架构、信任边界、输入面,产出到
architecture.md和coverage-ledger.json(覆盖账本)。 - 覆盖度驱动的猎洞:从账本单元派生隔离的 hunter 子代理,各自记录检查项,再用 coverage critic 找盲区。
- 候选验证 :每个候选漏洞交给一个全新的验证 Agent,任务是"试图推翻它"。
- 结构化输出 :写
confirmed/needs_validation/rejected三类记录到findings.json,用report-schema.json做校验。 - 独立复核:新 Agent 再验一遍最终记录,重大替换会触发又一次独立验证。
- 报告 :从已验证记录生成
REPORT.md等三份产物。
两个设计细节很见功力:
对抗式验证。README 的设计原则是:检查某个发现的 Agent 永远不是发现它的 Agent(原文直译)。LLM 有强烈的确认偏误------让它发现自己报的漏洞是真是假,它倾向于自我辩护。换一个没有沉没成本的 Agent 来证伪,是把人类安全评审中的 red team 机制搬进了 Agent 编排。
三态判定而非二态 。needs_validation 单独存在,要求写明"确切未解决的事实"且不给严重级别。传统 SAST 工具的痛点是误报淹没真问题,这里的规则是:只有源码可追溯、结果有观测边界的才算 confirmed;纵深防御的缺失只算加固建议,不算漏洞。这些约束都写在提示词层面,配合 validate-findings.cjs(零依赖 Node 校验器)在机器层面兜底。
几个务实的设计取舍
- 多轮运行是叠加的:官方测试里,单次运行大约只能找到多次运行累计漏洞的一半左右。这很符合直觉------采样本身就是 LLM 审计的核心瓶颈,靠重复跑换覆盖率,账本让后续运行能定向补盲区而不是重复劳动。
- 沙箱是硬性前置条件 :它要求目标代码的构建、测试、浏览器都在 OS 级沙箱里跑(禁外网、白名单环境、资源限制、只允许写临时路径)。做不到就不执行目标代码,结论一律停在
needs_validation。这是把"Agent 执行不可信代码"的风险放在了协议里而不是祈祷里。 - 攻击类知识是拆开的文件 :
AI-AND-LLM.md(提示注入、Agent/工具滥用)、SUPPLY-CHAIN-AND-RELEASE.md(依赖、CI、签名)、DATA-ISOLATION-AND-LIFECYCLE.md(租户隔离、备份迁移)等十几类。如果你只想让 Agent 审某类风险,可以裁剪。
怎么上手
bash
npx skills add https://github.com/cloudflare/security-audit-skill \
--skill security-audit
对 Agent 说 security audit this codebase 即可触发。几个实用提醒:
- 需要 Agent 支持工具调用和并行子代理------单 Agent 模型跑不出这套编排的价值。
- 首次跑可指定输出目录(默认输出到
~/security-audit-skill/下的run-目录)。 - 对
confirmed的结论别盲信,README 自己也说了这是"起点"而非成品系统。CI/CD 里跑它做增量检查是合理用法,替代渗透测试不是。
更大的启示
真正可复用的不是 Skill 本身,而是它示范的模式:把专业性拆成结构化流程 + 隔离子代理 + 机器可校验的输出契约。这三件套几乎可以平移到代码评审、性能排查、事故复盘等任何"多步推理 + 容易瞎编"的 Agent 任务上。当你发现你的 Agent 工作流总是产出幻觉结论时,问题往往不在模型,而在你给了它一个一步到位的提示词,却没有给它验证环节和输出契约。
MIT 协议,直接抄思路没障碍。