Cloudflare 在 GitHub 上开源的 security-audit 技能,把通用编码智能体改造成一名有流程约束的安全审计员。它并不给模型塞一份漏洞清单,而是把一次完整审计拆成六个阶段:侦察、按覆盖率猎取、候选验证、结构化输出、独立记录复核、目标中立报告;每个阶段由不同智能体承担,且挑出漏洞的智能体永远不能验证自己的发现。

仓库地址为 github.com/cloudflare/security-audit-skill,采用 MIT 许可,2026 年 6 月 18 日建仓,目前约 9,000 星、488 次 fork。更重要的是它的出身:Cloudflare 在其工程博客《Build your own vulnerability harness》中说明,这套技能正是公司漏洞挖掘流水线(harness)的种子——他们先写了约 450 行的 security-audit 技能跑在单个仓库上,调提示词直到挖出真实漏洞,之后才把这套编排扩展成覆盖全公司的系统。9 月 17 日,该项目登上 Hacker News 首页,也把关于 token 开销的争论一并带了上来。

装上就能用

它通过 skills.sh 的技能 CLI 安装:

npx skills add https://github.com/cloudflare/security-audit-skill \
  --skill security-audit        # 加 --global 安装到用户级

在目标代码库里对智能体说一句「security audit this codebase」或「find security vulnerabilities in ./src」即可触发。技能明确区分两种模式:guidance 模式(安全提问、定点排查、方法论咨询)只调用相关片段,不建目录、不写产物;full audit 模式(明确要求审计、渗透测试或要求产出报告)才会跑完六个阶段。若请求两者皆可,技能要求先问一个聚焦问题再动手。

完整审计会产出一组固定文件:architecture.md(架构与信任边界)、coverage-ledger.json(覆盖率账本)、findings.json(机器可读结论)、run-metadata.json(运行元数据),以及由最终记录派生的 REPORT.md、FINDINGS-DETAIL.md、NEEDS-VALIDATION.md。默认输出到 ~/security-audit-skill/<仓库名>/run-<N>;只有在用户明确指定、且父级确认该目录被版本控制忽略时,才允许写进目标仓库。

六个阶段

阶段做什么关键约束
1 侦察梳理架构、信任边界、输入面、既有证据,写出架构文档与初始覆盖率账本账本由父级独占维护
2 按覆盖率猎取从账本单元分配隔离的猎手,记录其检查,再用覆盖率批评者找缺口提示词逐字携带候选门槛与验证规则
3 候选验证每个去重后的候选交给全新验证者,任务是证伪验证者必须与发现者不同
4 结构化输出把三态结论写入 findings.json 并做 schema 校验校验器零依赖,只查格式不查正确性
5 独立记录复核全新智能体核对最终来源断言;发生实质替换需再找一名独立验证者复核结果回写并重新校验
6 目标中立报告由已复核记录派生三类报告报告中不包含任何在线探测指令

流程的落点只有两个终态:要么六阶段产物齐全且两个校验器都通过,要么显式记录 run_status: "incomplete" 并写明原因——不允许跑到一半停下,也不允许把没验证完的候选伪装成结论。

覆盖率账本才是这套东西的核心

真正让这个技能区别于「把提示词写长一点」的,是 coverage-ledger.json。它把审计对象拆成一个个覆盖率单元,每个单元由四个维度定位:入口面(surface)、信任边界(boundary)、子系统(subsystem)、攻击类(attack_class)。

这些维度都必须是「源码派生的稳定标识」,例如 src/router.ts#POST /users/:id、src/authz.ts#requireOwner、ATTACK-CLASSES.md#Access control。coverage_id 由这些引用按 UTF-8 百分号编码后以 :: 连接生成,显式禁止用「小写化/slug 化」这种有损方式派生——因为同一个源码对象必须在不同轮次里得到同一个 ID,账本才可能跨运行比对。单元状态有八种:planned、not_applicable、out_of_scope、in_progress、covered、candidate、blocked、deferred。

跨运行的可叠加性也是在这里实现的。技能预置了十一种「前次状态」,用来区分前一轮的证据在当前源码下是否仍然成立:只有相关源码与条件都没变的前次 confirmed 记录才能被带进本轮候选集;源码变了就必须新建复验单元;前次的 needs_validation、deferred、blocked 一律变成当前的工作,永远不能用来压掉新单元。Cloudflare 的措辞很直白:前一轮的源码版本号本身不是「这段路径没变」的证据。也正因如此,账本更新后必须立刻跑 validate-coverage-ledger.cjs,校验不过的账本不允许驱动下一次分配。

猎手被要求做什么

HUNTING.md 里有一段逐字复制进每个猎手提示词的核心方法。它不给漏洞清单,而是给一套动作:读代码要读到深处,跟随每个输入经过解析、身份、授权、规范化、状态、派生副本直到最终落点;比较兄弟路径、历史路径、批处理、重试、取消、迁移与错误路径;比较的是控制措施是否等价,而不只是是否存在。

方法要求从具体的不变量出发:先命名低信任主体与起始能力,再命名被接受的值或状态迁移,然后定位那个「本该拒绝/绑定/隔离/限制/吊销」的控制点,最后沿这条决策之后的源码路径追踪,停在最小可观测效果上——一条错写的假数据、一个错误的返回值、或者本地可见的共享资源变化。同时有明确的深度边界:只追能到达被分配边界、或该边界所依赖的路径,一旦不变量被证实或被推翻就停止搜索并记录,而不是继续扩大搜索面。

出口处是候选门槛,七条硬性规则,其中几条颇有态度:不得把崩溃夸大成代码执行、不得把普通工作量夸大成共享可用性、不得把同一主体的操作夸大成权限提升;如果关键事实既不在源码里也不能本地观测,就必须落到 needs_validation,且不允许给它任何严重级别。同一个根因在每种状态下必须使用同一个源码派生指纹,指纹里不得出现行号、波次、智能体、严重级别或结论。

三种结论,以及「不确定」的一等公民地位

结论被严格分成三态,字段结构各不相同:

  • confirmed:有完整的入口→传播→落点源码链路、有界可观测结果、完整前置条件,且没有可见的阻断层;只有它才带 severity 与 confidence。
  • needs_validation:一个有源码依据的边界假设被卡住了,必须写明确切的未决事实与安全的验证计划,且没有严重级别——它不是「置信度较低的确认漏洞」。
  • rejected:被源码证伪的候选,需要写明证伪理由。

严重级别用锚点校准:未认证者获得代码执行、完整数据存储访问或任意账号接管为 critical;完全击穿某个显式安全控制且后果真实(认证绕过、跨租户读写、存储型脚本执行、未认证的共享服务远程停止)为 high;边界违规但爆炸半径有限、前置条件少见或影响面狭窄为 medium。作者还给了 high/medium 的判别问句:这个被演示出来的结果,是完全击穿了一个显式控制,还是只是削弱了它?如果说不清具体损失,级别就该更低。

设计原则上,技能把「纵深防御缺口不是漏洞」写成了独立条款:如果 A 层已经挡住了攻击,B 层的缺失只是一条加固建议。同理,清单式偏离但没有受影响主体或资源的,属于排除项或加固项,不算发现。

把「别把机器搞坏」写进流程

这个技能的很大一部分文档其实在处理一件常被忽视的事:让智能体去测试不可信代码本身是有风险的。技能为此设了一条硬边界——源码检查保持只读;任何目标可控的构建、测试、进程、浏览器、模拟器、模糊测试与样本处理,只能在提供全部控制的 OS 级沙箱内运行:无外部网络(需要本地客户端/服务端流量时用隔离的 loopback 命名空间)、从空环境按白名单填充、目标与工具链只读、目标进程只能写自己的 scratch/、以及明确的 CPU/内存/进程/文件大小/磁盘/墙钟上限。

它还禁止了几乎所有「顺手一测」的冲动:不碰已部署端点和外部服务,不用真实凭据或生产数据,不做压力测试,不消耗付费 API 配额,不发布产物,不改动发布流程,也不在超过证明缺陷所需的最小效果后继续。产物回迁 artifacts/ 的过程被写成了一段十一步的复制规程:no-follow 打开、fstat 校验常规文件且链接数为 1、逐级校验父目录、独占创建目标、按已验证的大小复制——任何一步不可用就丢弃并保留 needs_validation。如果沙箱能力凑不齐,技能的选择是不执行目标代码,把缺失的沙箱能力记为阻塞项,并给出安全的人工验证方案。

预算与「不许假装查完了」

跑这种审计很贵,技能把成本直接变成可计数的单位:一个账本单元约等于一次猎手调用,一个存活候选约等于一到两次验证调用。用户设置的预算是「所有阶段的智能体调用次数上限」,并且有一道严格的门禁——在启动任何侦察智能体前,必须先扣掉四次基线侦察、每次猎取波次后的批评者、最终清洁批评者,以及至少一次验证调用;如果预算连这个最小值都不够,技能不启动任何智能体,直接要求更大的预算或更窄的范围,并记录 budget_cannot_fund_reconnaissance_and_reserves。

运行档位分三档:quick 只跑一波猎取加一次最终批评者;standard 按文档完整跑;deep 面向高风险或大目标,按子系统与生命周期模式拆分单元,并要求批评者波次跑到「干净通过」为止。范围受限的运行必须自述为部分覆盖。技能反复强调一句话:档位只改变广度与冗余,绝不改变证据标准——候选门槛、源码与本地执行的边界、needs_validation 纪律、schema 校验、对 confirmed 的独立复核,一条都不能省。批评者返回「没问题」只是它自己的判断,父级只有在另一名独立批评者也同意时才能声明覆盖完成。

领域配套与生态位置

除核心文件外,技能带了十个领域配套文件,用于给不同目标类型补充攻击类:内存安全与二进制、AI 与大模型(提示注入、智能体与工具、输出处理)、Web 协议与认证、客户端(DOM 注入、消息传递信任、界面伪装、原型污染)、供应链与发布、云与部署、RPC 与消息协议、资源耗尽与可用性、数据隔离与生命周期、桌面移动与本地 IPC。这些文件里是「要检查什么」的提示,落点仍然是那套候选门槛。

局限与争议

它并不便宜。Hacker News 的讨论中,有人报告在一个相对较小的 FastAPI 项目上就消耗了至少 15 万 token 并撞上会话上限,另一位开发者称在一个「中等规模」代码库上花掉 100 万 token 也没得到结果。技能自己也承认成本问题:预算门禁、quick 档位与「宁可声明未完成」的规则,本质上都是在承认一次跑不完。

覆盖率同样不能指望一次到位。Cloudflare 在博客中给出的实测结论是:单次运行大约只能发现多轮运行合计漏洞的一半,而且找到的偏向更简单、更不隐蔽的那些。这也是技能把「多轮叠加」写进设计的原因。

此外它要求运行环境提供 OS 级沙箱、支持并行子智能体的编码智能体、以及 Node.js,并明确表示这是「源码优先」的防御性工作流——它不会去探测真实系统。仓库自 6 月建仓以来共有 14 次提交,其中 9 月 10 日的一次重构把审计工作流、结论契约与两个校验器端到端重做了一遍,技能文档也提醒 API 与结构仍在变动。

核心总结

  • 定位:MIT 许可的编码智能体技能,出自 Cloudflare 漏洞挖掘流水线的前身,约 9,000 星
  • 流程:六阶段——侦察、按覆盖率猎取、候选验证、结构化输出、独立记录复核、目标中立报告
  • 核心机制:coverage-ledger.json 用四个源码派生维度定义覆盖率单元,coverage_id 确定性生成,支持跨轮次叠加
  • 对抗式验证:发现者与验证者必须是不同智能体;只有 confirmed 才有严重级别
  • 安全边界:目标可控代码只允许在无网络的 OS 级沙箱内执行,凑不齐控制就只记录阻塞项而不执行
  • 成本与覆盖:一个单元约等于一次智能体调用,预算不足时宁可不启动;单次运行约只能覆盖多轮合计漏洞的一半
  • 实测反馈:社区集中质疑 token 开销,小项目也能轻易烧掉十几万 token

原文:cloudflare/security-audit-skill(GitHub,MIT 许可);参考:Build your own vulnerability harness(Cloudflare Blog,2026-06-18)