Swarm Audit(群れ監査)
棚卸し → セクション分割 → セクションごとに1つのワークツリーと1つの監査エージェント → 各エージェントが検証済みの脆弱性をオーケストレータに報告 → 全脆弱性に対してチェーン監査 → 1つの統合レポート。オーケストレータは開始したワークツリーです。各成果物を先に進む前にユーザーに表示し、スコープとグループ化を決定してもらいます。
0. 事前準備
何よりも先に、3つのことを確定します。未確定のものはすべて1回のAskUserQuestion呼び出しでまとめて質問し(質問ツールがない場合はプレーンな形式で)、ユーザーが回答するまで停止します。
脅威モデル。 **/THREAT_MODEL.md を検索し、ベンダー提供ディレクトリやインストール済み依存関係ディレクトリはスキップします。テンプレートの <…> プレースホルダーがないファイルが存在する場合はそれを使用します。それ以外の場合は、ユーザーが既にクイックランを要求していない限り質問します。
- 脅威モデルを先に構築する(推奨): すべてのセクション監査担当者と批評担当者が、そのコントロールと対象外リストを使用するため、群れ全体での誤検出が減り、ビジネスロジックのバグが表面化します。事前に数ラウンドの質問が必要ですが、後続の監査で再利用できます。
- なしでクイックラン: 質問も脅威モデルもなし。セクション監査担当者は棚卸し結果とコードのみから作業します。群れが何を見つけるかを確認する最速の方法。ノイズが増える可能性があります。
構築の場合、このプラグインにバンドルされている security-audit スキルを、オーケストレータ内でSkillツールを通じて実行し、脅威モデルだけを要求し、手順1の前に THREAT_MODEL.md を待ちます。
分割戦略。 引数に --by-group [N] または --by-theme が含まれている場合はそれを使用します。それ以外の場合は質問します。
- テーマ別(推奨): セクションはコードの機能(認証、アカウント、支払い、注文、管理、サードパーティ統合ごとに1つ)に従います。各監査担当者はフロー全体を見るため、複数のエントリポイントにまたがるバグを発見できます。サイズは変動します。
- グループ別: ソース順に約N個(Nを質問、デフォルト25)の固定サイズグループに分割します。各監査担当者の負荷は均等で、判断は不要ですが、1つのフローが2つのセクションに分割される可能性があります。チェーン監査(手順6)である程度回復します。
スコープ。 ユーザーが何も指定しなかった場合、どのサービス、ディレクトリ、種類のエントリポイントをカバーし、何を除外するかを質問します。
1. エントリポイントの棚卸し
エントリポイントとは、外部からの入力がコードに到達するすべての場所です。HTTPルート、GraphQL/RPCハンドラ、Webhook、キューおよびイベントコンシューマ、外部データを読み取る定期ジョブ、CLIコマンド、ファイルまたはアップロードプロセッサ、クライアントサイドメッセージ、ディープリンク、IPCハンドラなどが該当します。
- 正規表現ではなく、リポジトリの言語用のパーサー(コンパイラや言語サーバーAPI、またはtree-sitter)を使用して検出します。登録は複数行にまたがり配列を使用するためです。スクリプトはスクラッチパッドに保持し、再実行可能にしておきます。
- エントリポイントごとに記録する項目: 種類、名前またはメソッド+パス、到達可能なユーザー(公開、ログイン済み、管理者、内部、署名付きWebhook)、ガード(認証、MFA、CAPTCHA、レート制限、入力スキーマ、署名チェック)、ハンドラ、ミドルウェア・デコレータ・フィルタ・インターセプタの全チェーン、
file:line。 - 見落としがちなもの:
- プレフィックスの下に登録されたネストされたルーター、コントローラー、ハンドラグループ、および渡されたオブジェクトに登録するヘルパー関数
- ヘルパー内部でグローバルに登録されたハンドラ(プレフィックスなし)
- 以前のプレフィックスレベルやキャッチオール登録から継承されたミドルウェア、フィルタ、ガード
- 1つのハンドラグループが2回登録されている場合: 一度だけリストし、エイリアスを記録
- 環境固有のエントリポイント(ステージング、デバッグ、フィーチャーフラグ): マークする
- 依存関係が登録するエントリポイント(認証サーバー、管理パネル、ヘルスチェック、ジョブダッシュボード): パッケージソースを読み、手動で追加する
- 不足しているものを見つける: クライアントコード(Webアプリ、モバイルアプリ、プロキシ、他のサービス)をgrepして、送信するすべてのパスまたはメッセージを検出し、トップレベルで登録されているすべてのものをリストします。追加するものをユーザーに質問し、除外したものとその理由を説明します。
- 棚卸し結果をオーケストレータのワークツリー内の
entry-points.md(またはユーザーが指定した名前)に書き込みます。
2. セクション分割
- テーマ別: サイズではなくコードの機能でグループ化し、1つのセクション内で異なる信頼境界(公開、パートナー、内部、ワーカー)を混在させないようにします。1つの監査担当者にとって大きすぎるテーマは分割します。
- グループ別: 棚卸し結果を順に約N個のグループに分割します。グループのサイズがわずかに変わる場合でも、同じファイルのエントリポイントは一緒に保持します。
- 提案された分割(名前、数、内容の1行概要、判断事項)を表示し、棚卸しファイルに書き込む前に承認を待ちます。
3. セクションごとに1つのワークツリー
各セクションのワークツリーを、オーケストレータの現在のコミットから作成します。これにより、すべてのセクションがユーザーがいるコードを監査します。command -v mori で見つかる場合は mori を、それ以外の場合はプレーンなgitを使用します。
| mori | git | |
|---|---|---|
| 作成 | mori new sec-audit-NN-<name> --from <current branch>; ワークツリーのパスを出力(~/.mori/worktrees/<repo>/ の下)— 記録する | git worktree add ../<repo>-sec-audit-NN-<name> -b sec-audit-NN-<name> |
| 依存関係 | リポジトリの .mori.json に post_create ステップがあればそれでインストール。なければ自分でインストール | 自分でインストール |
| 削除 | mori list --json で dirty を確認し、mori remove <branch> -f を実行。ブランチが残っていれば削除 | git status で確認し、git worktree remove <dir> と git branch -D <branch> を実行 |
detached HEADの場合はgitを使用します(git worktree add <dir> -b <branch> HEAD)。ワークツリーはバックグラウンドで作成します。
- 各ワークツリーにコピーするもの:
AUDIT_SCOPE.md(セクションのテーブル、列の注釈、「これらのエントリポイントのみ監査」)、完全な棚卸しファイル、脅威モデルが構築されたがまだコミットされていない場合は同じパスにそのコピー。 - オーケストレータに受信ボックスを作成:
<orchestrator>/.security-audit/swarm/<section>/。 - 分割をやり直す場合: 古いワークツリーとそのブランチを上記のように削除し(確認していない変更がある場合は強制削除しない)、再作成します。
4. セクション監査の並行実行
1つのブリーフをスクラッチパッドに書き、セクションごとに1つのバックグラウンドエージェントをそのブリーフを指して起動します。ブリーフには以下を含める必要があります。
- WORKTREE内でのみ作業し、そのエージェント指示(
CLAUDE.md、AGENTS.md)を読みます。WORKTREEの外部への書き込みは、INBOX(オーケストレータ内のセクションの受信ボックスの絶対パス)にのみ行われます。 - このプラグインにバンドルされている
security-auditスキル(またはユーザーが指定した別のスキル)を、Skillツールを通じて使用し、@AUDIT_SCOPE.mdにスコープします。クイックランの場合は、クイックランであることを伝え、質問を停止させます。スキルがない場合: 各入力をエントリポイントからシンクまでfile:lineでトレースし、すべての制御を通過して到達可能であることを証明し、到達可能でないものは破棄します。 - 脅威モデルがある場合: トレース前に全文を読み、そのエントリポイント、コントロール、対象外リストを使用し、決して書き換えません。クイックラン: 脅威モデルなし、作成もしません。質問は決してしません。
- すべての候補は、新たな批評サブエージェントに送られ、誤検出を前提とします。サブエージェントを起動できない場合は、自己批評し、脆弱性ごとにその旨を伝えます。
- Critical/High: 実際のエントリポイントを通じた失敗テストを、リポジトリのテストランナーで実行し、ツリー内に残します。
- 批評担当者が戻り次第、各脆弱性をINBOXに報告します。ファイルごとに1ファイル(
NN-<slug>.md)で、エージェントの出力が途切れても何も失われないようにします。フォーマットは以下。 - ブロックされた候補も報告: シンクに到達するが、セクションが提供できないもの(ID、トークン、被害者のアクション、漏洩した値、レース)を必要とするフロー。
status: blockedを使用し、何が不足しているかを正確に指定します。別のセクションがそれを提供する可能性があります。 - また、セクションレポートを
WORKTREE/.security-audit/<section>-<date>.mdに書き込みます。 - 厳格なルール: リポジトリの安全ルールに従うこと。マイグレーションやデータベーススクリプトは不可、git書き込み不可、外部サービスへの呼び出し不可。
- 最終メッセージ: 評決行、脆弱性ごとに1行、INBOXに送信したファイル数、未検証項目、監査スキルの呼び出し方法。
脆弱性ファイルのフォーマット:
---
id: <section>-NN
status: validated | blocked
severity: critical | high | medium | low | info
critic: independent | self
entry_point: <method + path or handler name>
needs: <攻撃者が事前に必要とするもの: アカウントタイプ、ID、トークン、被害者のクリック、タイミング>
gives: <攻撃者が後に得るもの: 漏洩した値、書き込みアクセス、セッション、金銭、コード実行>
test: <path or none>
---
1行の主張。
Trace: source `file:line` → … → sink `file:line`。
Repro: コードブロック内の正確な入力(リクエスト、メッセージ、ファイル)。
Controls checked: 確認した内容と、それがこれを阻止できない理由。
needs と gives はチェーン監査で結合されるものです。具体的に記述します(「何らかのデータ」ではなく「被害者の注文ID」)。
1つのセクションを自分でインライン監査しても構いません。同時サブエージェント数の制限により、一部の批評がブロックされる可能性があります。
5. チェーン監査前の再確認
すべてのセクションエージェントが完了したら、受信ボックスを読み、ファイル数を各エージェントの最終メッセージと比較します。次に、以下に対して自分で新しい批評を実行します。
critic: selfのHighまたはCritical- 暫定的、条件的、または「<他のサービス>に依存」とマークされた脆弱性: そのサービスのコードがあれば読み、問題を解決します。セクションだけでは見逃しがちな、2つのサービス間の境界のバグです。
脆弱性ファイルを批評担当者の深刻度で更新し、元の深刻度を was: 行に保持します。
6. チェーン監査
オーケストレータ内で棚卸しと脅威モデル(あれば)を手元に置き、受信ボックス全体に対して最後の監査を実行します。インラインで実行するか、完全な受信ボックスをブリーフに含めた1つのエージェントとして実行します。
- 重複排除。 同じ根本原因(同じシンクと同じ欠落制御)を持つ脆弱性を1つにマージし、それを利用するすべてのセクションとエントリポイントをリストします。2つのエントリポイントが1つのバグに到達する場合、それは2つの脆弱性ではなく、より広いブラスト半径を持つ1つの脆弱性です。
- 結合。 すべてのペアについて、1つの脆弱性の
givesが別の脆弱性(ブロックされた候補を含む)のneedsを満たすかどうかを確認します。また、一般的なエスカレーションパターンを探します。- 情報漏洩(ID、メール、トークン、内部URL)→ それを必要とするIDOR、アカウント乗っ取り、SSRF
- ユーザー列挙+レート制限の欠如 → クレデンシャルスタッフィングまたはOTPブルートフォース
- セルフXSSまたはHTMLインジェクション+CSRFまたはログインCSRF → 被害者に対するストアドXSS
- オープンリダイレクト+OAuthまたはマジックリンクフロー → トークン窃取
- マスアサインメントまたは弱いバリデーション+特権のある下流コンシューマ(ワーカー、管理ビュー、Webhook)
- レースコンディション+残高、クーポン、制限、または1回限りのアクション → 繰り返し利益
- 2つの低影響のビジネスロジックギャップが組み合わさって、資金を移動させたり制限を回避したりする
- 各チェーンを証明。 すべてのリンクで
file:lineと各ステップの正確な入力を使用して、エンドツーエンドでトレースします。コードにないリンクはチェーンではありません。発明せず、事前条件をどの脆弱性も公開アクションも提供しないリンクをカウントしないでください。 - 各チェーンを批評 新しいサブエージェントで、並行して実行します。サブエージェントは、実際にはステップが接続しない(異なるユーザー、異なるセッション、期限切れトークン、順序、1つのステップが別の制御で既に修正済み)と仮定し、チェーンの深刻度を返します。最終的な利益の影響×すべてのステップが一緒に発生する可能性、または「クリア」。
- CriticalまたはHighのチェーンをテスト 1つの失敗テストで、実際のエントリポイントを通じてすべてのステップを駆動し、オーケストレータのワークツリー内で実行します。
- 各チェーンを
<orchestrator>/.security-audit/swarm/chains/NN-<slug>.mdに脆弱性フォーマットで書き込み、links:に脆弱性IDをリストします。コンポーネントの脆弱性も保持します。
7. 統合レポート
オーケストレータ内に .security-audit/<scope>-combined-<date>.md を書き込みます。
- 重複排除後のカウント、チェーンは別途カウント(「3チェーン、2つが深刻度上昇」)を含む評決行。クイックランの場合、
security-auditスキルのreferences/REPORT_FORMAT.mdのクイックラン行で開始します。 - チェーンを最初に: ステップを番号付きリストで、入力と
file:line、最終的な利益、チェーン前後の深刻度、批評担当者、テストパス。各チェーンを壊す単一の修正を示します。 - Critical/Highの詳細: 正確な入力による再現手順、
file:lineによるトレース、利益と前提条件、修正、批評担当者、テストパスとテストが証明しないこと。 - Mediumテーブル、Lowリスト(折りたたみ)、ブロック解除されなかった候補(折りたたみ: 手がかりであり、脆弱性ではない)。
- セクション間のパターン。
- カバレッジのギャップと未検証項目(切断されたエージェント、受信ボックス数の不一致、本番設定、サードパーティの動作、自己レビューされた批評担当者)。
- 各ワークツリー内のレポートパスを含むセクションテーブル。
何もコミットしません。チャットの要約をチェーンとCritical/Highテーブルでリードし、最初にどの修正を出荷するかを示します。最も多くのチェーンを壊す修正を優先します。