Cloudflare 开源 security-audit-skill:让 Coding Agent 变成安全审计员

2 阅读3分钟

Cloudflare 把内部漏洞挖掘系统的"单仓库起点"开源了:security-audit-skill,一个让 Coding Agent 对代码库做结构化安全审计的 Skill。它不是一个模型,也不是一个扫描器,而是一套写给 Agent 的编排协议——这恰恰是最值得看的部分。

它是怎么干活的

整个审计分六个阶段:

  1. 侦察:让 Agent 先画地图——架构、信任边界、输入面,产出到 architecture.md 和 coverage-ledger.json(覆盖账本)。
  2. 覆盖度驱动的猎洞:从账本单元派生隔离的 hunter 子代理,各自记录检查项,再用 coverage critic 找盲区。
  3. 候选验证:每个候选漏洞交给一个全新的验证 Agent,任务是"试图推翻它"。
  4. 结构化输出:写 confirmed / needs_validation / rejected 三类记录到 findings.json,用 report-schema.json 做校验。
  5. 独立复核:新 Agent 再验一遍最终记录,重大替换会触发又一次独立验证。
  6. 报告:从已验证记录生成 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 审某类风险,可以裁剪。

怎么上手

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 协议,直接抄思路没障碍。