Swarm audit
盘点 → 分片 → 每个片一个工作区和一个审计代理 → 每个代理将验证过的发现报告给协调器 → 对所有发现进行链式审计 → 一份综合报告。协调器是你启动时所在的工作区。在每个工件展示给用户之前,由用户决定范围和分组。
0. 预检
在进行任何其他操作之前,先解决三件事。在单个 AskUserQuestion 调用中逐个询问每个问题(如果没有问询工具,则直接询问),然后停止,直到用户回答。
威胁模型。 找到 **/THREAT_MODEL.md,跳过 vendored 和已安装的依赖目录。如果存在一个没有模板 <…> 占位符的文件,则直接使用。否则,询问用户,除非用户已经要求快速运行:
- 先构建威胁模型(推荐):每个部分的审计者和评论者都会使用其控制列表和范围外列表,这能减少整个集群中的误报,并发现业务逻辑漏洞。前期会花费几轮提问;后续的审计可以复用。
- 不构建威胁模型直接快速运行:没有问题,也没有威胁模型;部分审计者仅根据清单和代码本身工作。最快看到集群发现结果的方式;但预期会有更多噪音。
如果选择 构建,则通过协调器的 Skill 工具运行此插件附带的 security-audit 技能,仅请求威胁模型,并在步骤 1 之前等待 THREAT_MODEL.md 就绪。
分片策略。 如果参数包含 --by-group [N] 或 --by-theme,则使用该策略。否则询问:
- 按主题分组(推荐):分片遵循代码的功能(身份验证、账户、支付、订单、管理、每个第三方集成一个)。每个审计者能看到完整的流程,因此可以发现跨多个入口点的漏洞。分片大小不一。
- 按组分组:按源代码顺序将入口点分组为大约 N 个的固定大小组 (询问 N,默认为 25)。每个审计者的工作量平均,无需判断,但一个流程可能被分割到两个分片中;链式审计(步骤 6)可以部分恢复这种分割。
范围。 如果用户未指定任何范围,询问要覆盖哪些服务、目录或入口点类型,以及要排除什么。
1. 盘点入口点
入口点是任何外部输入到达代码的地方:HTTP 路由、GraphQL/RPC 处理器、webhook、队列和事件消费者、读取外部数据定时任务、CLI 命令、文件或上传处理器、客户端消息、深度链接或 IPC 处理器。
- 使用仓库语言的解析器(其编译器或语言服务器 API,或 tree-sitter)来查找它们,而不是正则表达式:注册信息跨越多行且包含数组。将脚本保存在 scratchpad 中以便重新运行。
- 记录每个入口点的:种类、名称或方法 + 路径、谁可以访问(公共、已登录、管理员、内部、签名 webhook)、防护措施(认证、MFA、验证码、速率限制、输入模式、签名校验)、处理器、整个中间件/装饰器/过滤器/拦截器链、
file:line。 - 容易遗漏的部分:
- 在某个前缀下注册的嵌套路由器、控制器或处理器组,以及在传入的对象上注册的辅助函数
- 在辅助函数内部全局注册的处理器:没有前缀
- 从更早的前缀级或全捕获注册中继承的中间件、过滤器或防护
- 同一个处理器组被注册两次:列出一次,注明别名
- 仅限特定环境的入口点(staging、debug、功能标志):标记它们
- 依赖项注册的入口点(认证服务器、管理面板、健康检查、任务仪表盘):读取包源码,手动添加它们
- 找出缺失的内容:在客户端代码(Web 应用、移动应用、代理、其他服务)中 grep 所有它发送的路径或消息,并列出所有在顶层注册的内容。询问用户要添加哪些;说明你遗漏了哪些及其原因。
- 将清单写入协调器工作区中的
entry-points.md(或用户指定的名称)。
2. 分片
- 按主题分组:按代码功能分组,而不是按大小分组,且切勿将两个信任边界(公共、合作伙伴、内部、工作者)混合在一个分片中。如果某个主题对一个审计者来说太大,则拆分它。
- 按组分组:按顺序将清单切割成大约 N 个的组;当改变一个分组只需移动少数几个入口点时,将同一文件的入口点保持在一起。
- 展示提议的分片方案(名称、计数、每行内容、判断依据),在写入清单文件前等待批准。
3. 每个分片一个工作区
从协调器的当前提交为每个分片创建其工作区,这样每个分片审计的是用户当前的代码。当 command -v mori 能找到 mori 时使用它,否则使用普通 git:
| mori | git | |
|---|---|---|
| 创建 | mori new sec-audit-NN-<name> --from <当前分支>;它会打印工作区路径(在 ~/.mori/worktrees/<仓库>/ 下)——记录下来 | git worktree add ../<仓库>-sec-audit-NN-<name> -b sec-audit-NN-<name> |
| 依赖 | 如果有 .mori.json 的 post_create 步骤,则由其安装;否则手动安装 | 手动安装 |
| 删除 | 检查 mori list --json 中的 dirty,然后 mori remove <分支> -f;如果分支还存在,则删除它 | 检查 git status,然后 git worktree remove <目录> 并 git branch -D <分支> |
在分离的 HEAD 上,使用 git (git worktree add <目录> -b <分支> HEAD)。在后台创建工作区。
- 复制以下内容到每个工作区:
AUDIT_SCOPE.md(该分片的表格、列注释、“仅审计这些入口点”)、完整的清单,以及如果威胁模型已构建但尚未提交,则按相同路径复制一份副本。 - 在协调器中创建收件箱:
<协调器>/.security-audit/swarm/<分片>/。 - 若要重做分片:按上述方法删除旧工作区及其分支(切勿强制删除一个包含尚未审查的更改的工作区),然后重新创建。
4. 并行运行分片审计
在 scratchpad 中为每个分片编写一个简短说明,并启动一个后台代理指向它。说明必须包含:
- 仅在 WORKTREE 中工作;读取其代理指令(
CLAUDE.md,AGENTS.md)。WORKTREE 外部的唯一写入是到 INBOX(协调器中该分片收件箱的绝对路径)。 - 使用此插件附带的
security-audit技能(或用户指定的其他技能),通过 Skill 工具,限定范围为@AUDIT_SCOPE.md;如果是快速运行,告知这是快速运行,这样它就不会停下来提问。如果没有威胁模型:从入口点追踪每个输入到接收器file:line,证明它在每个控制之后都是可达的,丢弃任何不可达的东西。 - 如果有威胁模型:在追踪前完整阅读;使用其入口点、控制和范围外列表;切勿重写它。快速运行:没有威胁模型,不要创建。永远不要提问。
- 每个候选发现交给一个全新的评论者子代理,该代理假定这是一个误报;如果无法生成子代理,则进行自评,并在每个发现中说明。
- 严重/高:通过真实入口点编写一个失败的测试,使用仓库的测试运行器运行,并保留在树中。
- 评论者返回后立即将每个发现报告到 INBOX,每个发现一个文件 (
NN-<slug>.md),这样即使代理的输出被截断也不会丢失任何内容。格式如下。 - 同时报告被阻塞的候选:一个流动到接收器但需要该分片无法提供的内容(用户 ID、令牌、受害者操作、泄露的值、竞争条件)的流程。使用
status: blocked,并准确说明缺少什么;其他分片可能提供它。 - 同时将分片报告写入
WORKTREE/.security-audit/<分片>-<日期>.md。 - 硬性规则:遵守仓库的安全规则;不执行迁移或数据库脚本,不执行 git 写入,不调用外部服务。
- 最终消息:判定行,每个发现一行,发送到 INBOX 的文件数量,未验证的项目,以及如何调用审计技能。
发现文件格式:
---
id: <section>-NN
status: validated | blocked
severity: critical | high | medium | low | info
critic: independent | self
entry_point: <method + path or handler name>
needs: <what the attacker must have before: account type, id, token, victim click, timing>
gives: <what the attacker has after: leaked value, write access, session, money, code execution>
test: <path or none>
---
One-line claim.
Trace: source `file:line` → … → sink `file:line`.
Repro: exact input (request, message, file) in a code block.
Controls checked: what was looked at and why it does not stop this.
needs 和 gives 是链式审计的联接点:要写得具体(如“受害者的订单 ID”,而不是“一些数据”)。
你可以自己内联审计一个分片。注意并发子代理的限制可能会阻塞一些评论者。
5. 链式审计前重新检查
当所有分片代理都完成后,读取收件箱并将文件计数与每个代理的最终消息进行比较。然后自己对以下内容运行一个新的评论者:
- 任何标记为
critic: self的高或严重发现 - 任何标记为暂定、有条件或“取决于 <其他服务>”的发现:如果有该服务的代码,则阅读它并解决疑问。位于两个服务边界上的漏洞正是每个分片单独审计时会遗漏的。
用评论者评估的严重性更新发现文件,并在 was: 行中保留原始严重性。
6. 链式审计
在协调器中对整个收件箱进行最后一次审计,同时手头有清单和威胁模型(如果有)。以内联方式运行,或者作为一个代理,其说明中包含整个收件箱。
- 去重。 将具有相同根本原因(相同的接收器和相同的缺失控制)的发现合并为一个,列出触发它的每个分片和入口点。指向同一个漏洞的两个入口点是一个具有更广影响范围的发现,而不是两个。
- 联接。 对于每一对,检查一个发现的
gives是否满足另一个发现的needs,包括blocked候选。同时寻找常见的升级路径:- 信息泄露(ID、电子邮件、令牌、内部URL) → 需要的 IDOR、账户接管或SSRF
- 用户枚举 + 缺少速率限制 → 凭据填充或 OTP 暴力破解
- 自我 XSS 或 HTML 注入 + CSRF 或登录 CSRF → 对受害者的存储型 XSS
- 开放重定向 + OAuth 或 magic-link 流程 → 令牌窃取
- 批量赋值或弱验证 + 下游特权消费者(工作者、管理视图、webhook)
- 竞态条件 + 余额、优惠券、限制或一次性操作 → 重复获益
- 两个影响较低的业务逻辑漏洞,它们共同作用可以转移资金或绕过限制
- 证明每个链。 端到端地进行追踪,每个环节都有
file:line和每一步的确切输入。代码中不存在的环节不是链:不要发明,也不要计入一个需要由没有发现或公共操作提供的前提条件的环节。 - 用一个新的子代理对每个链进行评论,并行进行。它假定这些步骤在实践中无法连接(不同的用户、不同的会话、过期的令牌、顺序问题、某个步骤已被另一个控制修复),并返回链的严重性:最终影响 × 所有步骤一起的可能性,或者“已清除”。
- 测试 每个严重或高的链,在协调器工作区中编写一个失败的测试,驱动所有步骤通过真实的入口点。
- 将每个链写入
<协调器>/.security-audit/swarm/chains/NN-<slug>.md,采用发现格式,并包含links:列出发现的 ID。同时保留其组成部分的发现。
7. 综合报告
在协调器中写入 .security-audit/<范围>-combined-<日期>.md:
- 去重后计数的判定行,链单独计数(“3 个链,2 个提升了严重性”)。在快速运行中,以
security-audit技能的references/REPORT_FORMAT.md中的快速运行行开头。 - 首先列出链:步骤作为编号列表,包含输入和
file:line,最终收益,链式审计前后的严重性,评论者,测试路径。说明哪个单一修复能打破每个链。 - 严重/高写入:包含确切输入的复现步骤,包含
file:line的追踪,收益和前提条件,修复,评论者,测试路径以及测试未证明的内容。 - 中等级别表格,低级别列表(折叠),未被解除阻塞的 blocked 候选(折叠:它们是线索,不是已确认的发现)。
- 跨分片的模式。
- 覆盖缺口和未验证的项目(被截断的代理、收件箱计数不匹配、生产配置、第三方行为、自我审查的评论者)。
- 分片表格,包含每个工作区中的报告路径。
不要提交任何内容。首先在聊天摘要中列出链和严重/高表格,并说明哪个修复应该优先部署:优先选择能打破最多链的那个。