security-disclosure-triage について
Security Disclosure Triageは、対象リポジトリの脆弱性報告が開示に値するか、適切な深刻度はいくつかを判断する報告者向けスキルです。悪用可能性、信頼境界、公開済みバージョンを確認し、レポートと構造化データを作成します。
主な機能
- 01アドバイザリーの内容を再現・検証
- 02資産と実際の防御機構を追跡
- 03攻撃経路と信頼境界を評価
- 04ドキュメント・既存報告・公開状態を確認
- 05MarkdownレポートとJSON結果を作成
活用シーン
- 01対象リポジトリでの報告内容を評価
- 02影響と開示時の深刻度を判定
- 03責任ある開示に向けた検証記録を作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ superagent-ai/ skills --skill security-disclosure-triageインストール後、Claude Code で/security-disclosure-triageを入力して読み込まれたか確認します。
詳細
セキュリティ開示のトリアージ
あなたは報告者側の立場でアドバイザリを検証します。対象リポジトリに関する指摘が実際に開示可能な脆弱性かどうか、また妥当な深刻度がどの程度かを判断します。結果は責任ある情報開示のプロセスに使われるため、誤った確認や深刻度の誇張は、メンテナーの時間を浪費し、報告者の信頼を損ないます。
基本方針(最初に読んでください。すべての初期判断基準を定めます)
これはメンテナー向けのクローズ判定トリアージではありません。誤りによるコストが逆です。メンテナーは実際のバグを誤ってクローズしてはなりません。あなたはバグでないものを誤って確認してはなりません。具体的で実行可能な悪用経路が示されるまでは、「開示する価値はない」を初期判断としてください。
このスキルでは、以降のルールとして次の2点を徹底します。
- 再現は必要ですが、それだけでは不十分です。「コードがアドバイザリの説明と一致する」ことはトリアージの出発点であり、結論ではありません。該当するコードが存在するからといって、対象資産に到達できること、生成物を利用できること、またはその動作が意図されていないことを意味するわけではありません。
- **アドバイザリに記載された
severity/CVSS/CWEは検証対象の主張であり、引き継ぐべき値ではありません。**実際に生じる影響から独自に深刻度を導き出し、差異があれば指摘してください(通常は、より低い深刻度になるはずです)。
入力
アドバイザリ(title、source、repo、source URL、severity、CVSS、CWE、description)と、現在の作業ディレクトリである対象リポジトリのチェックアウトを受け取ります。アドバイザリと対象に範囲を限定してください。広範な一覧表示より、対象を絞った検索を優先してください。対象リポジトリのドキュメントを読んでください。「意図された動作」は、それを読まずには判断できません。
判定手順
以下の手順を順に実行してください。手順 7 までは処置を決定しないでください。
1. 構造を再現する。 アドバイザリが問題としている正確なコードを見つけます。reproduces ∈ {true, partial, false} を判定します。コードは説明どおりに実際に動作しますか? false の場合はそこで終了し、not_reproducible とします。true/partial の場合は続行します。ただし、まだ何も割り当てません。
2. 資産と実際の保護機構を追跡する。 アドバイザリがリスクにさらされていると示唆する最重要資産(セッション、キー、シークレット、レコード、管理者権限など)を特定します。その資産を実際に保護している単一の仕組みを特定します。次に、指摘されているプリミティブがその保護機構そのものであり、単に関連する別の仕組みではないことを確認します。誤ったプリミティブに関する指摘は、誤認の原因として最もよく見られるものです。コードは実在しますが、資産そのものではなく、その周辺の何かを制御しているというケースです。
3. 実行可能な攻撃経路を構築する。 具体的に記述します。攻撃者は誰か、最初に何を持っているか、最後に何を手にするか、そしてその状態で実際に行動できるかを示します。漏えいまたは偽造が可能な成果物については、特に利用可能性を検証します。他者向けに暗号化された暗号文、推測不可能なサーバー側ポインターに対する署名、下流で独立して再検証される値は、利用できません。攻撃者が行動に使えるものを最後に手にする経路を書けない場合、判定は hardening_low 以下にとどめます。
4. 想定された動作と既知の事例を確認する。 対象のドキュメント/README/SECURITY.md/変更履歴を読みます。その構造がドキュメントに記載された意図的な機能である場合、再現性がどれほど高くても by_design です。既存の CVE/GHSA または既知の問題との重複を検索し、該当する場合は duplicate とします。ドキュメントにアクセスできない場合はその旨を明記して確信度を下げ、意図されていないと決めつけないでください。
5. 信頼境界を確認する。 前提条件が、オペレーターによる設定ミス、初回利用時の信頼確立、同一ホスト/同一ユーザーの既に信頼された状態、プラグイン/ローカルによる制御、またはオペレーターが管理するネットワークへの露出だけである場合は、operator_responsibility とします。対象の SECURITY.md に明示的な対象外の記述がないからといって、指摘が対象範囲内になるわけではありません。 アドバイザリが実際の境界越えの回避を示さない限り、これらのケースはデフォルトでオペレーターの責任です。
6. リリース済みの状態を確認する。 その構造がリリース済み/タグ付け済み/公開済みの成果物に存在するのか、このチェックアウトにしか存在しないのかを確認します。以下のパラメーター化されたコマンドを使用してください。クローンが浅い、タグが存在しない、またはパッケージ名が不明な場合は、リリース済みの状態を確認できません。この場合、バージョンの判定は inconclusive となり、それだけで disclose の判定を妨げます。検証できないバージョンについて、問題なしとする確認結果を決して出さないでください。
7. 攻撃者の視点で検証する — 自分の指摘をレッドチームで検証する。 disclose を割り当てる前に、開示すべきでないという最も強力な根拠を記述します。設計どおりの動作、誤ったプリミティブ、利用できない成果物、オペレーターの責任、重複、過大評価された深刻度、検証不能なバージョンを検討してください。その根拠が強い場合は、判定を引き下げるか、指摘を取り下げます。この検証を通過した指摘だけが disclose に値します。
8. 深刻度を導き出す。 深刻度 = 資産の価値 × 実際に得られる能力 × 前提条件のコストの逆数です。その値を明示し、アドバイザリの主張とどのように異なるかも示します。アドバイザリの数値をそのまま引き継いで設定してはならず、増加を正当化する新たな証拠がない限り、その値を上回ってはなりません。
厳格な上限(決定論的な下限 — 楽観的な評価より優先)
- 被害を受ける具体的な資産を持つ名前付きの被害者がいない場合、最大でも
inconclusive/hardening_lowです。 - 検出事項のプリミティブが資産の実際の保護機構と異なる場合、それは脆弱性ではありません。
hardening_lowまたはby_designとします。 - 漏えいまたは偽造可能なアーティファクトを攻撃者が利用できない場合、最大でも
hardening_lowです。 - 前提条件がオペレーター/初回実行/同一ユーザー/すでに信頼されている/ローカルの状態だけの場合は、
operator_responsibilityとします。 - 文書化された機能、または意図された機能の場合は、
by_designとします。 - 出荷された状態を検証できない場合、バージョンの判定は
inconclusiveです。リリースにコードが含まれていることが別の方法で確認されない限り、discloseは認められません。 - 重大度は、アドバイザリの主張より低い値をデフォルトとします。それと同等以上の値にするには、報告書に明示的な新しい証拠が必要です。
重大度の基準(構成要素ではなく、結果に基づく)
構成要素の種類(「ハードコードされたシークレット」、「認証のバイパス」、「チェックの欠落」など)は重大度ではありません。実際に生じる結果を評価してください。
- critical — 意味のある前提条件なしに、未認証または低権限の攻撃者が資産を恒久的に制御できる(RCE、アカウント/インスタンスの完全な乗っ取り、大量のシークレット漏えい)。
- high — 攻撃者が実際の信頼境界を越えて機密資産にアクセスできるものの、ある程度の前提条件(有効な認証情報、特定のロールなど)が必要、または影響範囲が限定されている。
- medium — 実際の境界に関する問題だが、重要な前提条件がある、影響が部分的である、または強力な緩和策がある。
- low — 対象範囲が狭い、厳しい制限がある、または価値の低い資産に関する問題。もっともらしいものの制約された攻撃経路がある、正確性または多層防御に関する問題。
- informational / hardening — 再現はするものの、利用可能な経路が実証されていない問題。修正する価値はありますが、脆弱性として扱うほどではありません。
判定とパイプラインのステータスへのマッピング
詳細な disposition を出力し、その後、パイプラインの3種類の status にマッピングします。
| disposition | 意味 | status |
|---|---|---|
disclose | すべてのゲートを通過しており、実際に利用可能で、意図されたものではなく、バージョンの根拠がある | confirmed |
hardening_low | 再現するが、利用可能な経路はない。修正する価値はあるが、脆弱性として扱うほどではない | vulnerability_grade: false、重大度は low 以下で confirmed |
by_design | 再現するが、文書化されている、または意図されたものである | not_reproducible |
operator_responsibility | 前提条件がオペレーター/信頼された状態だけである | not_reproducible |
duplicate | 既存のアドバイザリまたは修正ですでに対処されている | not_reproducible |
not_reproducible | コードの動作が説明と一致しない | not_reproducible |
inconclusive | 証拠(多くの場合、出荷された状態に関する証拠)が不十分である | inconclusive |
confirmed は、メンテナーが実際に対応する価値のあるものに限ります。重大度を大げさに説明しないと confirmed にしたくならない場合は、hardening_low 以下です。
キャリブレーションの基準(判定例 — この基準に合わせる)
- 遅延する認証フック。 あるルートが認証戦略のチェックをハンドラ後のフックに登録しているため、チェックはレスポンスの送信後に実行されます。再現性は正確です。しかし、返される成果物は攻撃者が復号できないエンドツーエンドの暗号文であり、サービスレイヤーの権限チェックも呼び出しを制限しています。実際のバグですが、利用できる被害者はいません → 低、
hardening_low。教訓:利用可能性と実際のガードの追跡(ステップ 2~3)。 - 初回起動時のブートストラップ。 認証不要のエンドポイントが、インスタンスの初期化前に最初のスーパー管理者を作成します。完全に再現できます。しかし、これは文書化されたヘッドレスプロビジョニング機能であり、唯一の前提条件は、初期化されていないインスタンスをオペレーターが外部に公開することです。→
by_design/operator_responsibility。脆弱性ではありません。教訓:ドキュメントと信頼境界(ステップ 4~5)。SECURITY.md に除外事項がない ≠ 対象範囲内。 - 公開されているデフォルト署名鍵。 設定にはリポジトリで公開されているデフォルトの Cookie 署名鍵が含まれており、デフォルトの本番環境でも有効です。再現できます。しかし、この鍵が署名するのは一時的なサーバーサイドのセッションハンドシェイク状態のみで、認証済みセッションには別のシークレットが使われ、公開されたデフォルト値もありません。→ 低、
hardening_low。教訓:そのプリミティブが、関連資産を実際に保護するものか、類似する別のものではないかを確認する(ステップ 2)。 - 継承された深刻度 + 機能しないバージョン確認。 アドバイザリは「クリティカル」と記されていますが、浅いクローンではバージョン確認コマンドが何も返しません。→「クリティカル」を引き継がないでください。バージョンの判定項目は
inconclusiveとなり、confirmedにはできません。教訓:ステップ 6 と 8。
出力成果物
判定が inconclusive の場合も含め、完了前に両方を作成してください。
TRIAGE_REPORT.md — 次の順序でセクションを記載します:Advisory(タイトル/出典/CWE と申告された深刻度を転記)、Disposition + derived severity(処置と導出した深刻度、および申告との差異)、Reproduction(コード参照、再現する点/異なる点)、Asset & guard(資産、その実際のガード、発見されたプリミティブがそのガードに当たるかどうか)、Exploit path(具体的に利用可能な経路、または経路がない理由)、Intended-behavior & prior-art、Trust boundary、Shipped state、Adversary pass(情報開示に反対する最も強い主張と、それが妥当だったかどうか)、Recommendation。生のエクスプロイトの詳細は適切な範囲に抑えてください。これはトリアージ記録であり、攻撃を可能にする PoC ではありません。
triage-result.json:
{
"advisory_id": "<source id or title>",
"status": "confirmed | not_reproducible | inconclusive",
"disposition": "disclose | hardening_low | by_design | operator_responsibility | duplicate | not_reproducible | inconclusive",
"reproduces": "true | partial | false",
"vulnerability_grade": true,
"claimed_severity": "<from advisory>",
"derived_severity": "critical | high | medium | low | informational",
"severity_divergence": "<one line: why derived differs from claimed>",
"asset": "<crown-jewel asset>",
"real_guard": "<the mechanism that actually protects it>",
"primitive_is_guard": true,
"usable_path": "<one-line concrete path, or null>",
"intended_behavior": "<documented? cite doc, or 'no'>",
"trust_boundary": "<crossed | operator-responsibility | n/a>",
"shipped_state": "<affected release/tag, or 'unverifiable: <reason>'>",
"adversary_pass": "<strongest counter-case, and whether it held>",
"code_refs": ["path:line"],
"confidence": "high | medium | low"
}
検証コマンド(対象に合わせてパラメーター化すること — プロジェクトをハードコードしないでください)
まずアドバイザリ/チェックアウトから対象のリポジトリのスラッグとパッケージ名を特定してください。プロジェクトを決めつけないでください。
git tag --sort=-creatordate | head -n 20 # empty on a shallow clone → shipped state UNVERIFIABLE
git rev-parse --is-shallow-repository # true → cannot ground version locally
git log -1 --format='%H %ci'
npm view "<resolved-package>" version --userconfig "$(mktemp)" # only if the package name is known
git tag --contains <fix-or-intro-commit> # only if a relevant commit is known
git show <tag>:<path> # confirm presence in a specific release
git rev-parse --is-shallow-repository が true の場合、または git tag が空の場合は、出荷状態を unverifiable と記録し、バージョンだけを根拠に判定を confirmed にしてはなりません。