attack-path-stitcher について
Attack Path Stitcher は、資産ごとの検証済み所見を、証拠に基づく攻撃経路グラフにまとめるセキュリティスキルです。確定経路と推定経路を分け、cloud-agent task #6 向けに JSON、DOT、Markdown のレポートを出力します。
主な機能
- 01資産とピボットのグラフ構築
- 02証拠に基づく7種類の検出器
- 03確定経路と推定経路の分離
- 04crown_jewel への到達性分析
- 05JSON、DOT、Markdown の出力
- 06読み取り専用処理とグラフ規模制限
活用シーン
- 01資産間の認証情報再利用の追跡
- 02crown_jewel への外部侵入口の特定
- 03確定経路と推定経路の順位付き確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ transilienceai/ communitytools --skill attack-path-stitcherインストール後、Claude Code で/attack-path-stitcherを入力して読み込まれたか確認します。
同梱ファイルreference/edge-detectors.md
詳細
攻撃経路の連結
Validation Run タスク(#3)では、資産ごとに確認済みの所見が生成されます。実際の攻撃者リスクは攻撃チェーンにあります。資産 A の所見によって認証情報が漏えいし、それを使って資産 B の所見が可能になり、さらに資産 C へと侵入範囲が広がります。このスキルは、そのグラフを構築します。
cloud-agent タスク #6 にマウントされています。
トリガー
毎日の Cron(デフォルトは 03:00 UTC)。Validation Run タスクのバッチ完了後に再実行する場合もあります。
ワークフロー
- 入力を読み込みます。
validated/*.json— すべてのエンゲージメントにわたる、確認済みの所見。artifacts/org-surface.json— 組織全体のサーフェスグラフ(資産、サービス、ネットワークゾーン、信頼関係)。findings/finding-NNN/evidence/raw-source.txt— 連結時に認証情報/トークンを抽出するために使用します。
- 資産ノードを構築します。
org-surface.json内の資産ごとに 1 つのノードを作成し、tier、services、network_zone、trust_relationshipsを属性として設定します。 - エッジを構築します — 検出されたピボットごとに 1 つのエッジを作成します。7 つの検出器については
reference/edge-detectors.mdを参照してください。- 認証情報の再利用(A で漏えいした認証情報を B の認証に再利用)
- 共有シークレット/API キー(同じシークレットが 2 つの資産の証拠に存在)
- 信頼ゾーンをまたぐ推移的なアクセス(ゾーン X 内の A から、同じゾーン X 内の B へ暗黙的に到達可能)
- AD パスのホップ(kerberoast/DC sync/RBCD のチェーン)
- クラウド IAM ロールチェーン(侵害された資産から assume-role)
- SSRF → 内部資産への到達(A の SSRF によって B の内部エンドポイントに到達)
- サプライチェーン(
source-code-scanningの SBOM に基づき、A が B の依存関係にある)
- 到達可能性の閉包を計算します。
crown_jewelティアの各ノードについて、エッジを逆方向にたどる BFS を実行し、そこへ到達できる外部公開ノードをすべて見つけます。これらを「エントリーポイント」としてマークします。 - グラフを
artifacts/attack-paths.jsonに、人が読める DOT ファイルをartifacts/attack-paths.dotに書き込みます(Graphviz でレンダリングできます)。
実装はグラフの構築を処理する tools/chain-merger.py を通じて実行されます。このスキルはツールが参照するルールを提供し、反復処理はツールが行います。
出力
{OUTPUT_DIR}/
artifacts/
attack-paths.json # nodes, edges, entry_points, crown_jewel_paths
attack-paths.dot # Graphviz source
attack-paths.md # ranked list of distinct paths (human read)
attack-paths.json のスキーマ:
{
"generated_at": "2026-05-13T03:00:00Z",
"nodes": [
{"id": "asset42", "tier": "revenue", "services": ["http/443"], "zone": "dmz",
"external": true, "findings": ["finding-012", "finding-018"], "max_cvss": 9.8}
],
"edges": [
{"src": "asset42", "dst": "asset77", "detector": "credential-reuse",
"via_findings": ["finding-012", "finding-019"],
"evidence": "credential (userpass) present in evidence of asset42 and asset77",
"feasibility": 1.0}
],
"entry_points": ["asset42", "asset05"],
"confirmed_paths": [
{"jewel": "asset99", "paths": [
{"hops": ["asset42", "asset77", "asset99"],
"edges": [{"src":"asset42","dst":"asset77","detector":"credential-reuse","feasibility":1.0,"via_findings":["finding-012"]},
{"src":"asset77","dst":"asset99","detector":"ssrf-reach","feasibility":1.0,"via_findings":["finding-024"]}],
"feasibility": 1.0, "max_cvss": 9.8, "path_class": "confirmed"}
]}
],
"inferred_paths": [
{"jewel": "asset99", "paths": [
{"hops": ["asset05", "asset99"], "edges": [...],
"feasibility": 0.5, "max_cvss": 7.5, "path_class": "inferred"}
]}
],
"truncation": {
"edge_cap_hit": false, "depth_truncated_count": 0,
"topn_dropped_count": 0, "max_depth": 8, "edge_cap": 50000
}
}
RFP §3.3 への準拠における重要事項:confirmed_paths に含まれるのは、すべてのエッジの実現可能性が 1.0 であり、かつ各エッジが少なくとも 1 つの検証済みの所見を引用しているパスのみです。これらが RFP で求められる「確認済みの攻撃パス」です。inferred_paths には、PoC の証拠がないトポロジー/サプライチェーンのホップが含まれます。これらはアナリストのレビュー用に提示されますが、risk-prioritiser による修復 SLA の分類からは除外されます。
ルール
- エッジには根拠が必要です。 ピボットを裏付ける証拠が少なくとも1件の検出結果に含まれている場合にのみ、エッジを記録します。推測によるエッジは作成しません。
- 双方向性を前提にしてはいけません。 A から B に到達できても、B から A に到達できるとは推論しません。それぞれの方向に個別の証拠が必要です。
(src, dst, detector)で重複を排除します。 同じホップを可能にする検出結果が複数ある場合は、1つのエッジにまとめ、via_findingsにすべての検出結果を列挙します。- 実現可能性は
{1.0, 0.5, 0.25}のいずれかです。 信頼性の高い PoC の再実行は 1.0、条件付き(競合、タイミング、特定のユーザーなど)は 0.5、理論上(論理的には成立するが、実証されていない)は 0.25 です。 - パスの列挙数を制限します。 各クラウンジュエルについて、クラスごとに(確認済みと推定を分けて)上位10件のパスを、
feasibility × max_cvss / hop_countの降順で返します。優先順位付けの後続処理向けに、グラフ全体はattack-paths.jsonに保存されます。 - 読み取り専用です。 Stitcher は PoC を再実行せず、
findings/にも触れません。読み取りのみを行います。 - グラフのサイズを制限します。 エッジの構築は50,000件で停止し、パス検索の深さは
--max-depth(デフォルトは8ホップ)で上限を設けます。後続の利用側がパスの欠落を検出できるよう、JSON にtruncation.edge_cap_hit、truncation.depth_truncated_count、truncation.topn_dropped_countを出力します。 - 確認済みと推定の区別は必須です。 すべてのエッジの実現可能性が1.0であり、かつ各エッジの
via_findingsが空でない場合にのみ、そのパスをconfirmed_pathsに含めます。信頼ゾーンのみ、共有シークレットのみ、サプライチェーンのみの連鎖はinferred_pathsに含めます。この区分によって、「確認済みの攻撃パス」という RFP-§3.3 の主張が保証されます。 - 入力時にスキーマを適用します。
tools/chain-merger.pyは、finding_idまたはassetが欠落している行、あるいはverdict != "VALID"の行をvalidated/{id}.jsonから破棄し、stderr に WARN を出力します。上流のバリデーターはprojects/rfp-3.2/task-03-validation-run.mdのスキーマに準拠する必要があります。
参考資料
reference/edge-detectors.md— 具体的なシグナルパターンを含む7つの検出ルールです。projects/rfp-3.3/task-06-attack-path-stitcher.md— cloud-agent の実行時契約です。