用 Cloudflare Security Audit Skill 审查一个小仓库,并看懂 AI 报出的漏洞
如果你的项目里混着几个 eval()、硬编码密钥,或者前端直接拼 SQL 字符串,你可能已经能感觉到“需要检查了”。但你更清楚:安全扫描工具满天飞,报告却像天书。
本文的目标很明确:用 Cloudflare 开源的 Security Audit Skill 给一个小仓库做一次有范围、可复现的审查,并且把 AI 生成的报告真正读懂——知道哪些该修、哪些要追问、哪些可以直接忽略。
适合人群:会在本地使用编程 Agent、能读代码和运行终端命令的开发者。
读完你将能够:
- 安装 Skill 并给 Agent 交代任务(范围、模式、输出位置一次写清楚)
- 读取报告与覆盖记录,快速区分「已确认」「待验证」「被否决」的发现
- 把一项有依据的问题转成具体的修复任务
一、先说清楚:这不是“一键扫雷”,而是一个工作流
Cloudflare 的 security-audit-skill 是一种编排 Agent 执行安全审计的自动化工作流。通过 skills.sh 提供的 Skills CLI 即可轻松安装。整个审计流程严格划分为六个阶段:
- 侦察:分析目标架构、信任边界、输入面与覆盖范围。
- 按覆盖搜查候选:根据侦察结果筛选潜在问题点。
- 独立 Agent 验证:对候选进行独立确认并尝试构建反证。
- 结构化记录与账本校验:整理发现并核对格式与记录一致性。
- 独立 Agent 核对:复核最终源码、结果影响及修复措施。
- 报告生成:基于完整记录与覆盖分析生成最终审计报告。
理解这一点,就能明白为什么后面要强调:Agent 能力、运行环境与任务表述方式,直接决定审计是停在“聊表面”还是真正触及架构与实现。
二、安装与基础运行
1. 使用 Skills CLI 安装
本 Skill 由 Cloudflare 维护,借助 skills.sh 提供的 Skills CLI 工具,项目安装命令直接在目标项目目录中执行。
npx skills add https://github.com/cloudflare/security-audit-skill --skill security-audit
- --global 参数用于安装到用户级,省略该参数则为项目级;安装范围仅限这两者。
- 安装过程会显示提示,请按指引选择将 Skill 安装到具体的 Agent。
2. 运行环境前提(通用能力)
在调用前,确保你的编程 Agent 具备以下通用能力:
- 支持工具调用(Tool Use),并能并行启动子 Agent;
- 能访问 Node.js 运行时(仅用于两个独立校验脚本:格式与覆盖账本一致性校验);
- 能按自然语言理解任务目标,并在迭代中读取/写入结构化记录。
若目标 Agent 缺少必要工具或并行子 Agent 能力,必须先补齐这些运行前提;否则无法保证审计顺利启动或生成正确报告。
3. 启动方式:没有“专用终端启动”这回事
installation 完成后,进入支持该 Skill 的编程 Agent 会话,直接发送自然语言任务即可。
本教程不需要额外的 shell 启动命令,也不会要求你在仓库外运行一个长期守护进程。
输出路径说明(默认):
- 默认输出路径为
~/security-audit-skill/<repo-name>/run-<N>,其中<N>为下一个未使用的整数,该路径始终位于目标仓库之外,避免污染源码库结构。 - 如要在仓库内部放输出,必须:
- 由你明确选择目录;
- 并在
.gitignore中整体忽略该目录(避免被提交)。
4. Skill 本身不会自动建立隔离
security-audit-skill 不承诺提供构建/测试/复现环境的自动沙箱。
目标代码的构建、测试或运行时观察,应按最小可行安全原则自行约束:
- 在 OS 强制沙箱环境中运行。
- 禁止外网访问,仅按需允许隔离的 loopback 通信。
- 从空环境启动,显式注入仅包含安全变量的必要配置。
- 将目标和工具链设为只读,进程权限限制为仅向指定 scratch 目录写入。
- 沙箱需强制限制目标进程的 CPU、内存、进程数、单个文件、磁盘占用和运行时间;测试必须使用虚拟身份与数据,且资源限制应实际强制执行,而非仅扫描输入或依赖元数据声明。
若运行目标代码所需的沙箱条件未齐备(如超时、内存或CPU限制缺失),则暂停执行目标代码,避免资源失控。对于已有源码支撑的候选项,可保留在 needs_validation 中等待后续补齐,同时记录具体阻碍因素与拟定的适用验证计划。
三、给出一个“一次到位”的任务示例
下面是一个可直接复制粘贴到支持该 Skill 的编程 Agent 会话中的自然语言请求。它同时满足了:
- 明确范围(路径、文件);
- 要求 full audit 的报告产物;
- 指定 profile 为 quick,适合快速初检;
- 指定外部输出目录,避免仓库被写入;
- 要求记录 commit/变化/覆盖与未完成项;
- 留白给后续单独修复阶段。
对当前仓库的 src/auth 和 src/api 进行访问控制安全审计:
- 使用 full audit 的报告产物(完整证据链 + 结构化结论);
- profile 设为 quick:
- 先做一轮hunter扫描与基础覆盖复核;
- 每个候选问题交给一个新验证者,合并候选验证与最终记录复核;
- 保留结构化输出与两个 Node.js 脚本的格式/账本校验。
- 输出目录使用仓库外的 ~/audits/my-project-auth(不要写入仓库内);
- 报告中必须包含:
- 当前 commit ID 与工作区变更摘要;
- 实际覆盖范围与未覆盖区域;
- 已验证问题、置信度及建议修复;
- 标记为 needs_validation 的未完成项与后续执行计划。
在确认范围内,仅审计访问控制相关逻辑(认证、授权、令牌处理、输入校验等),不要发散到通用代码风格或性能问题。
随后我将另行开启一个会话专门讨论修复方案与回归验证。
执行后,Agent 会按上述约束启动六个阶段的工作流:从侦察→候选生成→独立 Agent 核实→结构化记录与脚本校验→最终核对→报告生成。审计结束时会明确告诉你哪些已解决、哪些需要人工介入或环境提升才能继续推进。
四、报告结构:只记核心文件
跑完一轮,进入输出目录。主要关注这几份文件:
run-metadata.json
本轮范围、源版本、完成状态、使用模式、覆盖记录概要等“元数据”。architecture.md
对审查涉及的模块/架构的简要理解(Full Audit 侦察的主要产物)。coverage-ledger.json
“覆盖账本”:哪些文件/路径被实际检查了,哪些被忽略或受阻;不仅记录文件清单,还包含检查单元与证据状态。findings.json
机器可读的发现列表,含 verdict(结论)、证据、路径等。REPORT.md
人类可读的主报告(必读)。FINDINGS-DETAIL.md
展开已确认的 medium/high/critical 项的详细说明;低严重度项通常参考 REPORT.md 和 findings.json。NEEDS-VALIDATION.md
待验证的线索:有证据但缺关键事实或执行条件。
不要指望每一行都读懂,关键是在 REPORT.md → FINDINGS-DETAIL/NEEDS-VALIDATION → coverage-ledger 这三者之间反复对照。
五、看懂 REPORT.md
阅读报告时建议按以下三个动作进行:
- 首先核对 profile(审计配置)、scope(范围声明)、源版本、完成状态以及未被覆盖的项目。
- 随后将内容分为 confirmed(已确认发现)与 needs_validation(待验证发现)两部分分别阅读。
- 最后对照 coverage-ledger 中的 blocked、deferred 和 out_of_scope 记录,并参考独立加固建议。
六、三种 verdict:如何判断一个发现成立
- confirmed:必须包含完整源码路径、明确的成立条件,以及受控环境下的实际观察结果(包括具体执行的输入与输出)。
- needs_validation:需要源码支持依据、确切的阻碍原因以及清晰的验证计划;此分类下完全省略 severity 字段。
- rejected:需要有确凿证据推翻该候选项;仅因范围外或单次未复现不足以自动判为否决。
七、一个具体例子:访问控制链路怎么读
先看一个“读取”场景里的典型问题与正确修复思路。
场景假设:
- 系统中有一个虚拟用户 A,已通过可信的 session/token 认证,请求者身份可被识别为 A。
- 有一个对象(例如某条记录、某个文件),其对象 ID 为 object_id,按业务规则只应允许用户 B 读取。
- 当前的读取链路大致如下:
- 入口:使用 object_id 直接读取对象;
- 下游:处理逻辑继续基于该对象做展示或操作;
- 关键点:在入口和主要下游都没有执行“请求者是否有权访问该对象”的判断。
如果在受控的本地验证中,虚拟用户 A 成功读到了属于 B 的私有内容,那么有三件事同时成立:
- “完整源码路径”:从入口读取到被返回使用的代码位置是清晰可追溯的;
- “成立条件”:缺失对象授权校验是造成越权的核心原因;
- “实际结果”:在受控环境下确实发生了未预期的读操作。
这三者结合,就足以支持对该问题的“已确认”。
修复思路应聚焦在“读取链路强制加入对象授权判断”:
- 依据可信认证身份(A)与对象归属规则,明确请求者是否有权访问指定对象;
- 回归测试至少应覆盖三种典型情况:
- A 读取自己的对象:应当成功;
- A 读取 B 的私有对象:应当被拒绝;
- 未认证/无效身份请求:按约定被拒绝。
常见误区提醒:
- 仅判断“用户是否存在”、“是否启用”或“ID 是否在合法范围内”,并不等同于完成了身份认证和对象归属检查;
- 即使开启了日志,日志本身不会阻止越权访问,它只是记录已发生的行为。
八、待验证与被否决:什么时候可以先放一放
在安全评估中,并非所有“看起来可能有问题”的地方都要立刻当作漏洞处理。我们需要把候选问题分成三类:“待验证”、“被否决”和“真正成立”,并说明它们在什么条件下可以暂时搁置。
待验证(needs_validation)
当源码或配置信息不完整时,有些问题只能先标记为“待验证”,而不是直接升级为漏洞。
例如另一条身份传递链:
- 源码中信任字段 x-user-id;
- 但当前不清楚:该值是否由可信网关在认证后覆盖?客户端能否绕过网关直连后端?部署证据不足。
此时应准确列出缺失的事实,如:
- 网关层是否在入口统一改写/校验 x-user-id;
- 是否存在允许客户端直连后端的配置或接口;
- 对应服务与网关之间的调用关系是否受控。
请负责人检查这些配置后再安排“受控本地验证”。注意:
- 不要直接把“条件不明”判为“已发生漏洞”;
- needs_validation 没有 severity,它只是表示:有线索,但缺少确认证据。
- 若一时补不齐信息,就保持“未解决”,并明确后续负责人和触发验证的条件。
被否决(rejected)
只有当源码分析、已观察到的行为或现有防护措施确实推翻具体候选时,方可判为 rejected;一次未复现本身不足以作为否决依据。
沿用刚才的读取场景:
- 入口表面上没有显式的对象授权校验;
- 但深入调用链路后发现:实际调用的下游函数在获取对象时,会基于可信请求者身份核对对象归属;
- 示例中的对象读取操作必须经过下游授权函数,该函数根据可信请求者的身份核对对象归属权限。
此时若源码与受控验证均显示:A 尝试读取 B 的私有对象时被拒绝,则该项“缺对象授权”的主张被推翻。
要点在于:
- rejected 否决的是“这一项具体候选问题”,而不是对整系统安全做出断言;
- 当来源、架构或配置发生变更后,结论需要重新评估。
小结
无论是待验证还是被否决,关键都在于:
- 用可复现的受控验证代替猜测;
- 明确“成立条件”与“支撑证据”;
- 让修复任务从已确认的条件、结果和最小改动出发,而不是从模糊的风险印象出发。
九、一次零 confirmed,怎么办?
零 confirmed 通常不代表“没漏洞”,而更可能是范围、覆盖或阻塞点的问题:
-
核对范围与账本
- 结合 coverage-ledger.json 判断哪些单元被 blocked(受阻)、deferred(递延)或 out_of_scope(在范围外)。
- 常见情形:关键部署事实缺失、依赖版本未解析、非源码资产未被纳入扫描。
-
调整审计配置而非盲目重跑
- quick 本来就是 full audit 的 profile,适合快速体检;若需更细粒度,可切换到 standard 或 deep。
- 档位与 scope 是独立可调的:当前默认 standard,可针对特定模块扩大 scope 或更换 profile 重新扫描。
- 重复运行不会宣称“已穷尽漏洞”:每个轮次受限于当时的配置、版本与事实完备度。
-
决策下一步
- coverage-ledger 保留纯覆盖缺口;对有源码支撑的候选问题,若缺关键事实或执行条件则记为 needs_validation,需附具体 blocker 与适用验证计划,缺执行条件本身即为 blocker,无需强制可执行验证。
- 若范围确实不足(如未包含子仓库或 Docker 镜像),则定义新的 scope 并重新执行,而不是纠结于当前轮次的 confirmed 数字。
十、把报告变成修复任务
将确认与待验证项转化为可执行任务时,需确保每个任务具备足够的上下文与验收标准:
-
对已 confirmed 的发现
- 源位置:精确到文件与行号(可追溯到调用路径中的关键片段)。
- 完整成立条件:复述该发现被确认为成立所需的所有前提(配置、权限、输入来源等)。
- 修复任务需记录受控环境下实际执行的输入命令、观察到的执行结果,以及受影响的具体权限边界。
- 最小有效修复:针对该路径与条件的具体改动,而非泛化建议。
- 回归案例:说明修复后需验证的场景或测试点,确保未来变更不会复现相同风险。
-
对 needs_validation 的发现
- 安排补事实任务:记录待查信息(如“确认服务 X 是否启用 XX 参数”),明确责任人与检查方式。
- 待验证任务条目应保留具体的缺失事实与验证计划;needs_validation 分类下的记录中不包含 severity 字段。
- 验证计划应具体可执行:例如“查看生产环境配置 Y"、“核对身份映射表 Z”。
-
数据来源
- medium/high/critical 的详细信息可从 FINDINGS-DETAIL.md 读取;其他 confirmed 从主报告或 findings.json 确认。
- 每个任务都必须能对应到原始证据,避免“凭感觉”生成工单。
十一、常见困惑快速答
-
为什么 REPORT.md 里几乎没有 rejected?
- 报告优先聚焦可用证据支持的项目;rejected 仅在对争议解释或覆盖决定必要时以指纹方式提及,保持版面简洁。
-
有没有“检出能力保证”,比如承诺不漏报某个漏洞类型?
- 没有。是否查过供应链、AI 生成代码、Web/认证等,取决于本轮 scope 与 coverage-ledger 的实际记录,而非通用话术。
-
有一个文件名或可执行片段就足够确认漏洞吗?
- 不够。必须回到源码、完整调用路径、权限边界以及受控的实际结果进行核对;片段本身只是线索。
-
多个仓库管理时,这个 Skill 能否自动串联?
- 本 Skill 以单仓库为起点。跨仓库的持续流水线与 harness 属于 Cloudflare 企业文章后续方案,非当前默认能力范围。
-
我机械校验了 JSON 字段和账本一致,能算验证完成吗?
- 不能。机械校验确保数据可用;独立验证者需核实事是否成立、条件是否满足、边界是否清晰。
-
为什么 needs_validation 没有 severity?
- needs_validation 之所以没有 severity,是因为它仍有决定性事实待查;应先保留具体阻碍和验证计划,只有对已成立的 confirmed 发现才分配严重程度。
十二、最后一句
用 Security Audit Skill 做审查,关键不是“跑一次”,而是:
- 明确范围与期望
- 把报告当作可追踪的证据链,而不是情绪化的警报
- 能把每一条
confirmed问题,转成一个具体的修复任务与回归用例
当你下次打开 REPORT.md,不再问“这到底是不是真的”,而是问“它凭什么成立?我能用什么最小改动去验证或修复?”
你就已经从一个被工具牵着走的人,变成了真正会用安全审计工具的人。