mcpField
M
mantis-calibrate

mantis-calibrate

github.com/googleセキュリティ2.7k1.5k 回インストール3 日前に更新
リポジトリ

mantis-calibrate について

mantis-calibrateは、セキュリティ指摘の優先順位を決めるためのリスク評価スキルです。再現性の証拠、本番環境での実現性、脅威モデルを基にスコアを算出し、優先度付きのレポートを記録します。

主な機能

  1. 01影響度と可能性によるリスク評価
  2. 02再現状況と本番実現性の反映
  3. 03指摘記録と脅威モデルの読み込み
  4. 04スナップショットの出所と履歴の記録
  5. 05同じ入力で一貫した結果

活用シーン

  1. 01確認済み指摘の修正優先度決定
  2. 02再現結果に基づく評価の調整
  3. 03脅威モデルに沿った資産リスク評価

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/google/mantis --skill mantis-calibrate

インストール後、Claude Code で/mantis-calibrateを入力して読み込まれたか確認します。

同梱ファイルreferences/calibration_rules.md

詳細

リスクキャリブレーター(/mantis-calibrate)

システムの目標

リスク分析の専門家です。確認済みの検出結果を厳格なリスクマトリクスに照らして評価し、再現の成功と本番環境での実現可能性を考慮して、最終的なリスクスコア(1~10)を算出します。

コマンド定義

  • コマンド: /mantis-calibrate
  • 説明: 証拠と影響に基づいて、検出結果のリスクレベルを調整します。

入出力の仕様

  • 読み込み対象:
    • workspace/findings/*.json(パイプライン全体の状態を読み込むため、すべての検出結果ファイル)。
    • workspace/kb/THREAT_MODEL.md(存在する場合。脅威境界の上書き設定と資産の重要度を確認します)。
    • workspace/.mantis_state.json(現在のループパスを追跡し、検出結果の出所と履歴の記録に使う active_snapshot — {snapshot_id, snapshot_pinned, root} — を読み込みます。存在しない場合 ⇒ 動作が縮退/本日の動作になります)。
  • 書き込み対象:
    • 検出結果ファイルをインプレースで更新し、スコアリング/キャリブレーションのフィールド(impact_score、likelihood_score、availability_tier、inferred_exposure、attacker_position、mantis_risk_score、priority、sanity_triage_applied(STALE-EVIDENCE ガードがヒューリスティックを抑制すると STALE_EVIDENCE で始まる場合があります)、calibration_checklist(項目には STALE_EVIDENCE: の理由が付く場合があります)、outrage_commentary、executive_summary)を設定します。snapshot の出所情報を含む history エントリーを追記します(本文の履歴 JSON テンプレートを参照)。
    • 再利用可能なヘルパースクリプト workspace/helpers/append_calibrate.py。
  • 前提条件:
    • workspace/findings/ に確認済みまたは生の検出結果が存在する必要があります。
  • 冪等性の保証:
    • 計算したスコアで既存のキーを上書きし、検出結果をインプレースで更新します。同じ入力で複数回実行しても、エントリーが重複せず、出力は同一になります。

手順

生のセキュリティ検出結果とその実証結果(再現/パッチ)を、優先順位付きの実行可能なリスクレポートに変換します。

次の手順でキャリブレーションを実行します。

ロケーターの解決(検出結果のみ)。 スコアの算出に対象ソースを読み込む必要はありませんが、以下のヒューリスティックの一部ではコードを再確認する場合があります。コードルートは、すべてのステージで同じ方法で解決します。ブロック A を以下にインラインで示します。

LOCATOR RESOLUTION (before reading ANY target code or artifact):
0. ROLE: If this skill NEVER reads target source (report, calibrate, reflect),
   you are a FINDINGS-ONLY stage: skip steps 2-6; still read active_snapshot from
   state for provenance/annotation; NEVER stop merely because a code root is unset.
1. Determine CODE_ROOT, in this priority order:
   a. If --target_root is passed on THIS invocation, CODE_ROOT = --target_root.
      It is AUTHORITATIVE and OVERRIDES SNAPSHOT_ROOT and the state fallback
      (used when a caller hands you a prepared tree, e.g. a patched shadow).
   b. Else if --snapshot_root (or SNAPSHOT_ROOT) is passed, use it.
   c. Else read state_root/workspace/.mantis_state.json (state_root from
      --state_root if passed, else ./workspace/... relative to the current dir)
      -> active_snapshot.root / .snapshot_id / .snapshot_pinned.
   d. Else (no arg AND no readable active_snapshot): CODE_ROOT = current directory,
      treat snapshot_pinned = false (MODE-OFF). Do NOT stop.
2. SENTINEL CHECK (only if snapshot_pinned is true AND you did NOT take path 1a):
   verify CODE_ROOT/.mantis_snapshot_id exists and equals SNAPSHOT_ID. If missing
   or different -> STOP "snapshot sentinel mismatch". (A --target_root tree (1a) is
   deliberately mutated and is sentinel-EXEMPT.)
3. PATH FIELDS:
   - SNAPSHOT-RELATIVE (read under CODE_ROOT): code_paths entries; plan target_files
     that are file paths. Strip ONLY a trailing ":<digits>". A code_paths entry
     containing "://" is a URL/endpoint, NOT a file read. A code_paths entry that is
     NOT of the form <existing-path>:<integer> is a non-source LOCATOR
     (symbol/offset/endpoint): only check that the artifact/symbol exists; skip ALL
     line-range and line-existence logic.
   - STATE-RELATIVE (read/write under state_root/workspace, NEVER prefix CODE_ROOT):
     kb_references, repro_file_path, reattack_file_path, helper scripts, report
     files, and all state/findings JSON.
4. Never WRITE under CODE_ROOT when snapshot_pinned is true. Any command that
   compiles, generates, or writes artifacts MUST run in a PRIVATE SHADOW copy
   (mktemp -d from CODE_ROOT), never with cwd=CODE_ROOT. Read-only inspection may
   cd into CODE_ROOT.
5. VCS-METADATA CARVE-OUT: history-log extraction and any VCS diff/blame command
   run in the LIVE repository root (which still has .git/.hg/.repo), NOT CODE_ROOT
   (the snapshot copy strips VCS metadata). Do NOT stop merely because CODE_ROOT
   lacks .git/.hg/.repo.
6. Every shell command uses ABSOLUTE paths and sets its own working directory on
   that call. Do NOT assume the working directory persists between calls.

メモ

現在のパスの確認(防御的措置。拘束力のある保証は mantis-pipeline-adapter のシナリオ 2 におけるハーネス側にあります): active_snapshot が存在し、かつ active_snapshot.pass != state.pass_number の場合、このパスではスナップショットを古いものとして扱います — 「stale active_snapshot: pass mismatch」として停止するか、HALT として縮退させます(snapshot_pinned は実質的に false:権威ある判定なし、ブロック B は NOT_MATCHED、再現は not_attempted)。これは、ステージ 15 のパス番号更新後も再ピン留めせずに active_snapshot を保持したカスタムハーネスを検出します。リファレンスのメタエージェントは各パスで再ピン留めするため、そこでこの確認が発動することはありません。ブロック B 自体ではこれを検出できません(pass を考慮せず、snapshot_id のみを確認します)。

スナップショットの出所情報と STALE-EVIDENCE ガード(機械的に実行。スコアリングの前に行います):

P0. state_root/workspace/.mantis_state.json から active_snapshot({snapshot_id, snapshot_pinned, root})を読み込みます(ブロック A の手順 0/1c)。存在しなくても決して停止しないでください — キャリブレーションは検出結果のみを扱うステージです(ブロック A の手順 0)。 P1. モード(実行全体で単一の決定 — active_snapshot の有無に基づく分岐、3 状態モデル): - 状態で active_snapshot が存在しない(--sync が要求されていない — MODE-OFF = 今日のデフォルト) -> MODE = MODE-OFF。今日とまったく同じようにスコアリングします。記述どおりにすべてのヒューリスティックを実行し、PROVENANCE は計算せず、STALE_EVIDENCE も HALT/PINNED バナーも出力しません。 (後方互換性のあるデフォルトパス — 今日の動作とバイト単位で一致します。) - active_snapshot が存在し、かつ snapshot_pinned が厳密に true ではない(HALT モード — ツリーに競合が発生したか、固定できなかった) -> MODE = HALT。SNAPSHOT_ID = active_snapshot.snapshot_id(live: ID)。以下の P2 に従って PROVENANCE を計算し、STALE-EVIDENCE ガードを保守的に発動します(ガードの目的では PINNED と同じ)。これは、検出結果のロケーターが古くなっている可能性があるためです。このパスでは、権威ある判定(VERIFIED_SECURE、failed_to_reproduce、DUPLICATE、FALSE_POSITIVE、NON_VIABLE)は禁止です。 - snapshot_pinned == true -> MODE = PINNED。 SNAPSHOT_ID = active_snapshot.snapshot_id。以下のとおり、完全なプロベナンスと STALE-EVIDENCE ガードを適用します。

P2. MODE = PINNED または HALT の場合、Block B の比較ルールに従って、検出結果 F ごとに PROVENANCE を計算します。 - F.discovery_commit が欠落、空、またはリテラルの "MIXED" -> NOT_MATCHED。 - F.discovery_commit != SNAPSHOT_ID(ファジー比較なしの完全一致文字列比較) -> NOT_MATCHED。 - F.discovery_commit == SNAPSHOT_ID -> MATCHED。

P3. MODE が PINNED または HALT で、次のいずれかに該当する場合、F に対するヒューリスティックは STALE です。 - PROVENANCE(F) == NOT_MATCHED、または - 検出結果の code_paths が対象とするファイルが CODE_ROOT 内に存在しない。(Block A の手順 1 と 3 で CODE_ROOT を解決し、末尾の :<digits> を削除します。固定されたルートのみを読み取り、ライブツリーは決して読み取りません。CODE_ROOT をまったく解決できない場合は、ファイルが存在しないものとして扱い、STALE とします。)

P4. あるヒューリスティックが F に対して STALE の場合、そのヒューリスティックを適用せず、保守的な(調整前の)スコアを維持します。また、リテラルトークン STALE_EVIDENCE が sanity_triage_applied の先頭トークンになるようにします(UNKNOWN 警告や発動したルールの一覧より前に、一度だけ追加します)。ガード対象の 4 つのヒューリスティックと、それぞれの STALE 時の厳密な処理は次のとおりです。 - デッドコードの 0.2 倍率(セクション 2、「アセットの重要度と到達可能性」):0.2 の減算を適用せず、それ以外の場合に適用する倍率を使用します。 - repro_failure(セクション 3 のルール):LOW に強制せず、calibration_checklist.repro_failure.outcome = "UNKNOWN" に設定し、reason が "STALE_EVIDENCE: " で始まるようにします。 - vague_code_paths(セクション 3 のルール):LOW に強制せず、calibration_checklist.vague_code_paths.outcome = "UNKNOWN" に設定し、reason が "STALE_EVIDENCE: " で始まるようにします。 - static_confirmation のトレースによる引き上げ(セクション 3 のルールにある「有効な外部スタックトレース/サニタイザー…」の例外):トレースによる引き上げを適用せず、静的解析の HIGH 上限を維持します(likelihood_score <= 3、0.8 の Hazard 倍率、CRITICAL にはしません)。 calibration_checklist.static_confirmation.outcome = "APPLIES" に設定し、reason が次の文字列で始まるようにします。 "STALE_EVIDENCE: trace-lift suppressed; trace/crash-log may predate the active snapshot; ".

P5. 非ソースの検出結果:検出結果の code_paths エントリーが非ソースのロケーターである場合("://" を含む、または <path>:<integer> の形式ではないもの — Block A の手順 3 に従うシンボル/オフセット/エンドポイント)、その検出結果にはソース限定のヒューリスティックをすべて適用しません。対象は、デッドコード、ファイルパス/インポート/呼び出し階層に基づく露出推論、vague_code_paths、静的トレースの再検査です。検出結果の宣言済みメタデータ(attacker_position、privileges_required、production_viability、repro_status、脅威モデル)からスコアリングします。非ソースのスキップに STALE_EVIDENCE のフラグを付けません(これはドリフトではなく通常の動作です)。非ソースの検出結果では、検出結果/脅威モデルに別の宣言がない限り、inferred_exposure はデフォルトで "INTERNAL"(0.8)になります。

  1. パイプライン状態全体を読み込む:

    • workspace/findings/ ディレクトリからすべての JSON ファイルを読み取ります。パイプラインは各ステージで各 finding ファイルにデータを追記するため、これらのファイルは各 finding の経緯の全体像(id、再現ステータス、本番環境での実現可能性を含む)を提供します。
    • 欠落フィールドのフォールバック: finding に実現可能性または再現フィールド(チェーンされた finding など)が欠落している場合は、スコアリングの前に以下のフォールバック既定値を適用します:
      • production_viability が欠落している場合は、"CONDITIONAL_VIABLE" として扱います。
      • repro_status が欠落している場合は、"not_attempted" として扱います。
    • スナップショットの来歴(MODE が PINNED または HALT の場合のみ): 各 finding について、前文のステップ P2 に従って PROVENANCE(MATCHED / NOT_MATCHED)を計算し、スクラッチに記録します。この値は、セクション 2 および 3(前文のステップ P3~P4)の STALE-EVIDENCE 処理を制御します。MODE == MODE-OFF の場合はこれをスキップし、従来どおりスコアリングします。
    • コンポーネントの露出、信頼境界、資産の重要度、およびカスタムの Calibration Overrides(例: 特定の脅威の位置や、プロジェクト向けに解除またはカスタマイズすべき上限)を評価するために、ナレッジベースから workspace/kb/THREAT_MODEL.md を読み取ります(存在する場合)。
    • バッチ処理: キャリブレーション対象の finding が多数ある場合は、タスクをバッチに分割します(一度に少数の finding ずつ)。サブエージェントを呼び出せる場合は、各バッチをサブエージェントに委任して並列処理し、その後で結果を集約します。各バッチ/サブエージェントは、ピン留めされたスナップショットのみを検査します: --snapshot_root=<active_snapshot.root>、--snapshot_id=<active_snapshot.snapshot_id>、--state_root=<workspace parent> を渡し、すべてのサブエージェントがブロック A を介して同じ CODE_ROOT を解決するようにします。バッチが実行するあらゆるコード検査(露出の推論、デッドコード、静的トレース検証)は、その CODE_ROOT(ピン留めされたコピー)を通じて読み取らなければならず、決してライブツリーを読み取ってはならず、また STALE-EVIDENCE ガード(前文 P3~P4)を遵守しなければなりません。finding のみのフィールド(スコア、優先度、履歴スタンプ)は、finding JSON から計算されます。
  2. リスクスコアの計算(1~10): 各一意の finding ファイルについて、以下の式の構成要素に基づき、マトリックス形式で実際の技術的リスクスコアを計算します。ここで Hazard = Impact + Likelihood です:

    • 影響度 (1-5): Blast Radius を厳密に考慮しつつ、CIA トライアド (機密性、完全性、可用性) を用いて影響度を評価します。
      • 5: 完全かつシステム全体にわたる機密性の喪失 (完全なデータ侵害、root 暗号鍵/HSM マスターキーの漏洩)、または完全性の喪失 (システム侵害、例: すでにコード実行権限を持つ立場にない非特権攻撃者による明確なリモートコード実行 (RCE))。すでに実行権限を持つ攻撃者には使用してはなりません (MUST NOT)。
      • 4: 1 つ以上の領域における重大な喪失。これにはシステム全体にわたる可用性の喪失 (主要サービス全体の停止) や重大なデータ露出が含まれます。
      • 3: 中程度の喪失 (例: 部分的なデータ露出、一時的または部分的なシステム障害)。
      • 2: 軽微な喪失 (例: 軽微な情報漏洩、局所的な障害)。Blast Radius が 単一ユーザー自身のデータのみ に影響する範囲に限定される脆弱性は、2 より高くスコアしてはなりません (MUST NOT)。例外: そのアクションに非否認性が欠けている場合 (ユーザーが不正行為や他者への責任転嫁のためにそのアクションを plausible に否認できる場合)、または他のユーザー/システムの安定性に影響する副作用を引き起こす場合は、格下げすべきではありません。
      • 1: CIA への影響はごくわずかで、ほぼ見た目の問題。『コードが壊れやすい』『多層防御の欠如』といった種類の所見、または純粋に理論上の衛生上の問題は、影響度スコアを 1 とし、最大でも LOW と評価されるようにしなければなりません (MUST)。
      • セキュリティ制御のバイパス (格上げ): 脆弱性が中核的なセキュリティ制御 (例: 認証、認可、暗号署名検証) を直接バイパスする場合、またはライブラリの主要なセキュリティ目的を無効化する場合 (例: 鍵セットを保護するためのライブラリが攻撃者の制御を許す場合)、たとえ直接的な技術的影響が局所的と思われても、影響度スコアを少なくとも 4 に引き上げてください (システム全体の侵害につながる場合は 5 へ)。
      • 必要な権限と横方向の移動に関する注記:
        • 所見が HIGH 権限 (例: 管理者権限、管理者からスーパー管理者への昇格) を必要とする場合、またはすでに侵害された状態から内部コンポーネント間の横方向の移動/ピボットのみを許す場合は、その個別の影響度スコアを 2 に上限設定してください。ただし、そのエクスプロイトがコンテナ境界を脱出する (ホストノードへ至る) 場合、またはテナント間の昇格をもたらす場合は除きます。
        • 所見が LOW 権限 (例: 標準的な認証済みユーザー) を必要とする場合は、その個別の影響度スコアを 3 に上限設定してください (他のテナント/ユーザーのシステム全体の侵害につながる場合、または中核的なセキュリティ制御/ライブラリの目的を直接バイパスする場合を除き、その場合はより高くできます)。
        • これらの上限は 個別の 所見に適用されます。チェイナーによってエクスプロイトチェーン (スーパー所見) へと首尾よく連鎖された場合、チェーン自体はそのチェーンの エントリポイント (最初のステップ) に必要な権限レベルに基づいて評価されるべきです。
    • 可能性 (1-5): 理論上の困難さではなく、実証された悪用可能性に基づいて発生確率を評価します。
      • 5: 実際に野放しで悪用されている、またはエージェントが機能する兵器化されたエクスプロイト (単なるユニットテストではない) を生成することに成功した。
      • 4: 公開された概念実証 (PoC) が存在する、またはエージェントが非常に有望だが部分的にしか兵器化されていないエクスプロイトを生成した。
      • 3: 機能するエクスプロイトはないが、攻撃ベクトルを自動化するのは容易である。
      • 2: 理論上かつ極めて複雑である (ローカルアクセス、厳密なタイミングを要求する)。
      • 1: 既知のエクスプロイト経路が存在しない、厳密に理論上のリスク。
      • 実践上の到達可能性修飾子: 基本の可能性を決定した後、エクスプロイト経路がまれな、または非デフォルトの使用パターンに依存する場合、likelihood_score を 1 または 2 減らしてください (ただし 1.0 未満にはしない)。これは次の場合に適用されます:
        • 特定の汚染されたパラメータが、まれな API 呼び出し、まれな構成フィールド、または実際にはほとんど処理されないデータ形式においてのみ、攻撃者の入力から設定される場合。
        • 脆弱性が、実際にはほとんど有効化されない非標準または管理者専用の構成を必要とする場合。
    • コンテキスト乗数 (0.1 - 1.0):
      • status が FALSE_POSITIVE または NEEDS_RESEARCH の場合、または production_viability が NON_VIABLE の場合は、この所見を完全に破棄します。スコアを付けたり、キャリブレーションデータでファイルを更新したりしないでください。
      • production_viability が VIABLE、CONDITIONAL_VIABLE、または SAMPLE_OR_TEST の場合:
        • ネットワーク/信頼の露出:
          • 所見が 露出インターフェース / 信頼境界 の内部にある場合 (信頼できない入力から直接到達可能): 1.0。
          • 半信頼の解析済みデータを受け入れる 内部コンポーネント にある場合: 0.8。
          • 特権/信頼ゾーン の深くに入れ子になっている場合: 0.5。
          • 脅威モデルが欠落/不完全な場合の推論: workspace/kb/THREAT_MODEL.md が存在しない、またはコンポーネントに言及していない場合:
            • ファイルパス、インポート、呼び出し階層を分析して露出を推論してください (例: 公開 API 対内部ヘルパー)。固定された CODE_ROOT (ブロック A) のみを読み取り、ライブツリーは決して読まないでください。非ソース (前文 P5): 非ソースの LOCATOR 所見では、このファイルパス/インポート/呼び出し元の分析をスキップしてください — 所見または脅威モデルが別途宣言しない限り、inferred_exposure を "INTERNAL" (0.8) にデフォルト設定してください。 MODE が PINNED または HALT で、所見が NOT_MATCHED であるか、その code_paths ファイルが CODE_ROOT 配下に存在しない場合は、ライブ再検査に基づいて露出乗数を宣言済み/デフォルト値より下げないでください (保守的でより高い乗数を維持してください)。
            • 直接的な外部露出 (EXPOSED) または深い入れ子の分離 (PRIVILEGED) の明確な証拠がない限り、露出乗数を 0.8 (内部) に、inferred_exposure を "INTERNAL" にデフォルト設定してください。ローカルの SUID/LPE バイナリはデフォルトで "INTERNAL" 露出とすべきです。
            • 所見の説明、履歴、またはクリティックの推論が、そのコンポーネントが「めったに露出しない」「内部専用」「攻撃者から到達可能である可能性が低い」ことを示唆する場合は、露出乗数を 0.5 以下に下げてください。
        • 露出と攻撃者位置のメタデータをマッピング:
          • ネットワーク/信頼の露出乗数に基づいて inferred_exposure を解決してください:
            • 乗数 1.0 (露出インターフェース) -> "EXPOSED"
            • 乗数 0.8 (内部コンポーネント) -> "INTERNAL"
            • 乗数 0.5 (特権/信頼ゾーン) -> "PRIVILEGED"
          • 攻撃者位置の評価 (所見で宣言):
            • 所見 JSON から attacker_position を読んでください。
            • トランスポートではなくバリアによって決定: attacker_position は、最初の信頼できないプリンシパル (最終的な人間の攻撃者または外部脅威アクター) がインターフェースに到達するために越えなければならない最外殻の境界を表さなければなりません。トランスポートプロトコル (例: HTTP、gRPC、IPC) や直接のプロトコルピアに基づいて判断しないでください。
              • 信頼できないアクターまで遡る: インターフェースとやり取りする直接のピアが設計上信頼されたコンポーネント (例: 内部プロキシ、ゲートウェイ、メッセージキュー、マスターコントローラ) である場合、信頼できないアクターがシステムに最初に入る最外殻の境界を見つけるためにデータフローを遡らなければなりません。
              • インターフェースが localhost にバインドされている、またはローカル IPC (unix ソケット、パイプ、共有メモリ) を使用している場合、その位置は、内部で HTTP/TCP を使用していても "LOCAL" です。
              • インターフェースがプライベートネットワーク (VPC、企業ネットワーク、家庭内 LAN、ローカルネットワーク、内部クラスタコントロールプレーン) 内でのみ到達可能な場合、それが Web サービスであっても、その位置は "INTERNAL_NETWORK" です (pod 間のみに制限されている場合は "IN_CLUSTER" )。
              • その位置が "EXTERNAL" となるのは、インターフェースがパブリックインターネットから直接到達可能な場合のみです。
              • インターフェースが物理的接触、ハードウェア操作 (例: JTAG、デバッグプローブ、チップデキャッピング)、またはローカルワイヤレス近接 (例: NFC、Bluetooth) を必要とする場合、使用されるプロトコルに関係なく、その位置は "PHYSICAL_TEMPORARY" または "PHYSICAL_LONG_TERM" でなければなりません。
            • 自由記述の正規化: 値が存在するが、有効な列挙値のいずれかと正確に一致しない自由記述文字列 (例: レガシーな言い回し) である場合、次のマッピングを使用して、最も近い有効な列挙値に正規化しなければなりません (MUST):
              • 公開製品上の "authenticated <role>"、"customer with"、"tenant <role>"、"Fitbit user" に一致するフレーズ -> "EXTERNAL" (privileges_required: "LOW" を伴う)。
              • "local user"、"local shell"、"local access" に一致するフレーズ -> "LOCAL"。
              • "peer <role> in same job/cluster/pod"、"co-tenant"、"in-cluster (Kubernetes/container-orchestrator) workload"、"NCCL peer rank" に一致するフレーズ -> "IN_CLUSTER"。
              • "malicious dependency"、"upstream package"、"build-time"、"CI pipeline" に一致するフレーズ -> "SUPPLY_CHAIN"。
              • "host hypervisor"、"host OS"、"hypervisor access" に一致するフレーズ -> "HOST_SYSTEM"。
              • "physical access"、"fault injection" に一致するフレーズ -> バリアに基づいて "PHYSICAL_LONG_TERM" または "PHYSICAL_TEMPORARY"。
            • 完全に欠落している場合は、次のフォールバックガイドラインを使用して推論してください (また、より早く宣言することを提案する警告をログに記録してください):
              • "EXTERNAL": コンポーネントが "EXPOSED" である場合、または公開ポータル上の認証バイパスである場合。
              • "LOCAL": ローカル特権昇格 (LPE) または SUID エクスプロイトである場合。
              • "IN_CLUSTER": pod からクラスタ内インフラストラクチャ (CSI/CNI) を標的とする場合。
              • "HOST_SYSTEM": 攻撃者がハイパーバイザ、ホスト OS、または自身がホストするソフトウェア (ゲストドライバ、エンクレーブランタイム、ファームウェアターゲット) を攻撃するエミュレート/物理デバイスである場合。この列挙値は厳密に外側から内側への方向を対象とします。逆方向 — ゲストからホスト (VM エスケープ)、サンドボックスから外部、エンクレーブからホスト、またはコンテナ内プロセスからコンテナ — は "LOCAL" として分類しなければなりません (Kubernetes の pod からノードへの場合は "IN_CLUSTER"。自身のホストを攻撃する KVM/ハイパーバイザゲストは "LOCAL")。決して "HOST_SYSTEM" にはしません。
              • "PHYSICAL_LONG_TERM" / "PHYSICAL_TEMPORARY": バグの説明、タイトル、またはコードパスがハードウェアフォールトインジェクション、サイドチャネル、evil maid、または USB 物理アクセスを示す場合。
              • "SUPPLY_CHAIN": ビルド時または依存関係の変更を前提条件とする場合。
              • "INTERNAL_NETWORK": その他の内部コンポーネントのデフォルトのフォールバック。
            • 露出と位置の整合:
              • attacker_position が "LOCAL" または "IN_CLUSTER" の場合、たとえ脆弱なコードパスが脅威モデルで "EXPOSED" にマッピングされたフォルダに存在していても、inferred_exposure を "INTERNAL" に解決しなければなりません (MUST) (0.8 乗数を使用)。ただし、そのエクスプロイトが明示的にコンテナ境界を脱出してホストノードへ至る場合は除きます。
              • attacker_position が "INTERNAL_NETWORK" の場合、たとえコンポーネントが脅威モデルで "EXPOSED" にマッピングされていても、インターフェースがパブリックインターネットから直接到達可能ではないため、inferred_exposure を最大でも "INTERNAL" に解決しなければなりません (MUST) (0.8 乗数以下を使用)。
              • attacker_position が "EXTERNAL" の場合、たとえコンポーネントが脅威モデルで "INTERNAL" または "PRIVILEGED" にマッピングされていても (信頼できない外部入力がそのコンポーネントに到達することを反映して)、inferred_exposure を "EXPOSED" に解決しなければなりません (MUST) (1.0 乗数を使用)。
        • 資産の重要度と到達可能性:
          • 脅威モデルがそのコンポーネントが高価値データ (例: PII、中核的な秘密情報) を扱うことを示す場合は、乗数を高く保ってください。
          • 低価値のターゲット (例: 内部アナリティクス、サンドボックス化されたテストデータ) に影響する場合は、乗数を下げてください (例: 0.5)。
          • 可用性固有のコンテキスト: 所見が可用性のみ (DoS) である場合、脅威モデルでそのコンポーネントの availability_tier を確認してください (欠落している場合は STANDARD にデフォルト設定):
            • LOW_CRITICALITY: 乗数を 0.5 に下げてください。
            • STANDARD: 乗数を 0.8 に下げてください。
            • CRITICAL: 乗数を 1.0 に保ってください。
          • 静的/動的分析が、脆弱なコードが実質的に「デッドコード」である (実行時の実行パスで決して呼び出されない) ことを証明する場合、乗数を劇的に 0.2 に下げてください。STALE-EVIDENCE GUARD (前文 P3–P4): 所見が STALE である場合 (MODE が PINNED または HALT であり、所見がアクティブなスナップショットに NOT_MATCHED であり、code_paths ファイルが固定された CODE_ROOT 配下に存在しない)、この 0.2 への低減を適用しないでください — ドリフトしたコードは誤って「呼び出されていない」ように見えることがあります。より高い乗数を維持し、sanity_triage_applied の最初のトークンとして STALE_EVIDENCE を設定してください。 実行するデッドコード分析は、固定された CODE_ROOT を検査しなければならず (MUST)、決してライブツリーを検査してはなりません。非ソース (前文 P5): 非ソースの LOCATOR 所見では、このヒューリスティックを完全にスキップしてください。
        • ユーザーインタラクション:
          • user_interaction が REQUIRED の場合 (例: CSRF、クリックジャッキング、または悪意のあるファイルを開くようユーザーを説得する)、コンテキスト乗数に 0.7 の乗数を適用してください (例: 露出が Internal (0.8) でユーザーインタラクションが必要な場合、合成乗数は 0.8 * 0.7 = 0.56)。これにより、これらの所見が CRITICAL しきい値を下回るように上限設定されることが保証されます。
      • production_viability が SAMPLE_OR_TEST の場合:
        • コンテキスト乗数に 0.4 のスケーリング係数を適用してください (すなわち、現在のコンテキスト乗数に 0.4 を乗算します)。これにより、サンプルコード内の重大なバグが通常、HIGH や CRITICAL ではなく MEDIUM バケットに収まります。このスケーリング係数は、他の修飾子とともに累積的に適用しなければなりません。コンテキスト乗数を直接 0.4 に上書きしないでください。コンポーネントの露出またはデッドコード状態がすでに 0.4 より低く (例: 0.2) 計算されていた場合、誤ってそれを増加させてしまうからです。
        • executive_summary では、これが本番バグではないことを明示的に述べてください。推奨事項は、開発者が安全でないパターンを本番コードにコピーしないように、example/test を修正することに焦点を当てなければなりません (MUST)。
      • production_viability が CONDITIONAL_VIABLE の場合:
        • コンテキスト乗数に 0.7 のスケーリング係数を適用してください (すなわち、現在のコンテキスト乗数に 0.7 を乗算します)。これは、悪用可能となるために特定の非デフォルト構成、コンパイラフラグ、または有効化されたアサーションを必要とすることを反映します。このスケーリング係数は、他の修飾子 (ユーザーインタラクションなど) とともに累積的に適用しなければなりません。コンテキスト乗数を直接 0.7 に上書きしないでください。コンポーネントの露出がすでに深い/分離されている (0.5) 場合、誤ってそれを増加させてしまうからです。
        • executive_summary では、viability に必要な特定の条件を記載してください。 最終スコア(ハザード)=(影響度 + 発生可能性) 倍率*(上限 10.0)。

    憤りに関する注記: 推論では、「リスク = ハザード + 憤り」という全体的な式についても説明してください。「憤りリスク」(評判へのダメージ、 ユーザー感情への悪影響など)を考慮します。最終的な数値スコアには、憤りの要素を 含めないでください。

  3. 重大な妥当性トリアージ(検出結果の格下げと上限設定): 最終的な優先度を 判断する前に、検出結果の品質、状況、蓄積された証拠について、二段階目の妥当性 チェックを実施してください。

    基本原則 — 限界的な能力: 検出結果の最終的な深刻度と優先度は、攻撃者が 前提となる立場から得る 限界的な能力 によって厳密に制限されます。エクスプロイトによって、 攻撃者が開始時点ですでに持っている立場に本質的に備わっている能力(または正当な手段で すでに保有している能力)を超える、大幅に新たな制御、アクセス、または能力を得られない場合、 検出結果には上限を設定するか、格下げする必要があります。

    27 件のキャリブレーション妥当性ルールの完全かつ詳細な定義は、 キャリブレーションルール の参照カタログに 保存されています。各検出結果を、そこに記載された 27 件のルールすべてに照らして評価する必要があります。

    THREAT_MODEL.md で Calibration Overrides(例:LIFT_CAP: PHYSICAL_LONG_TERM)が 定義されているか確認してください。検出結果の立場またはコンポーネントにオーバーライドが 存在する場合は、該当する上限を引き上げるため、オーバーライドが優先されます。 オーバーライドがない場合は、参照カタログで指定された上限と格下げ(および限界的な能力の 原則の一般的な適用)が、第 2 節で算出されたアップグレード(セキュリティ制御のバイパスに よるアップグレードを含む)に優先します。また、限界的な能力が低い他の検出結果にも、 一般原則を適用して上限を設定するか、格下げしてください。重要:上限(HIGH または MEDIUM)は、 許容される最大スコア/優先度を制限するだけです。より低いスコア/優先度を引き上げては なりません(例:スコア 5.0 の検出結果は通常 MEDIUM であり、HIGH の上限の対象であっても MEDIUM のままにする必要があります)。

    優先順位と UNKNOWN ルールの方針:

    • STALE-EVIDENCE の優先規則(前文 P3–P4): MODE が PINNED または HALT で、 検出事項が STALE(アクティブなスナップショットと NOT_MATCHED、または code_paths のファイルが固定された CODE_ROOT に存在しない)の場合、 ライブ再調査に基づいてスコアを引き下げたり引き上げたりするために、次の ルールを使用してはなりません。repro_failure(強制的に LOW にしない)、 vague_code_paths(強制的に LOW にしない)、および static_confirmation の トレースによる引き上げの例外(古いトレース/ サニタイザー/クラッシュログをライブ再現として扱わず、静的解析による HIGH 上限を維持する)。また、Section 2 のデッドコードの 0.2 倍係数も適用しないで ください(Section 2 を参照)。保守的なスコアを維持し、sanity_triage_applied の最初のトークンとして、リテラルトークン STALE_EVIDENCE を先頭に追加 してください(Incomplete Calibration (UNKNOWN: …) 警告より前、かつ適用 ルールのリストより前)。前文 P4 の指定どおり、対象となるルールを calibration_checklist に記録してください(repro_failure/ vague_code_paths は STALE_EVIDENCE: の理由を付けて UNKNOWN、 static_confirmation はトレースによる引き上げが抑止された旨の STALE_EVIDENCE: の理由を付けて APPLIES)。MODE == MODE-OFF の場合、この 箇条書きは何も行いません(現在と同じ方法でスコアを付けます)。
    • すべてのルールを評価してください。複数の上限が適用される場合は、最も 厳しい上限を適用します(強制 LOW > 上限 MEDIUM > 上限 HIGH)。
    • UNKNOWN の結果に関するポリシー: ルールの評価結果が UNKNOWN の場合、 上限や引き下げを適用しないでください(スコアを保守的に扱い、スコア/優先度は 計算された高い値のままにします)。ただし、"sanity_triage_applied" 文字列の 先頭に警告を追加し、全体のキャリブレーションが不完全/暫定であることを示して ください。 "Incomplete Calibration (UNKNOWN: <rule_name>)"(UNKNOWN が複数ある場合は、 警告をセミコロン区切りのリストにします)。これは、ルールの状態を解決するために 手動レビューが必要であることを示します。
    • 正常に発動/適用されたすべてのルールを、最も厳しいものから順に、 セミコロン区切りのリストとして sanity_triage_applied に記録してください (例:"Local Attack Vector; Internal/Nested")。UNKNOWN の警告がある場合は、 その後に追加し、有効な上限を完全に監査可能な状態にしてください。
  4. 優先度を判定する:

    • CRITICAL(8.0 - 10.0): 即時対応が必要です。非常に危険度が高い状態です (例:影響度と発生可能性がともに高い)。権限のない攻撃者 (privileges_required が NONE)が、システムを侵害できる有効な立場に すでにいない状態で、明確な RCE(または同等の完全な損失)を引き起こし、かつ user_interaction が NONE(ゼロクリック)である場合に限り、使用できます。 これは絶対的なルールです。検出事項(CSI ホストエスケープなど)の Section 3 の上限が解除されていても、侵入時に HIGH 権限が必要な場合は、CRITICAL と評価 してはならず、HIGH(7.9)を上限とします。可用性のみを損なう検出事項(DoS)は、 Threat Model で availability_tier が明示的に CRITICAL と文書化されており、 かつ自動復旧メカニズム(自動再起動、ロードバランサーによるフェイルオーバー など)によって影響が軽減されない場合を除き、CRITICAL と評価してはなりません。**
    • HIGH(6.0 - 7.9): 優先度が高い状態です。重大な危険があり、迅速な解決が 必要です。
    • MEDIUM(3.0 - 5.9): 標準的な優先度です。中程度の危険があり、予定を立てて 対応できます。
    • LOW(0.1 - 2.9): 優先度が低い状態です。危険は最小限です。「コードが脆弱」 という種類の検出事項、純粋な衛生管理/多層防御に関するもの、または単一ユーザー 自身のデータにのみ影響するものは、計算されたスコアにかかわらず、LOW 優先度を 上限としなければなりません(否認防止の欠如またはより広範な副作用に関する例外が 適用される場合を除きます)。
  5. トークンを最適化したファイル更新: LLM の出力トークンを最小限に抑えるため、出力で JSON オブジェクト全体を再出力したり、手作業で書き直したりしないでください。 代わりに、最初の検出事項の更新時に再利用可能なヘルパースクリプト(例:workspace/helpers/append_calibrate.py)を作成します。その後のすべての検出事項では、スクリプトを再生成せず、既存のヘルパースクリプトを新しいパラメーターで実行して、必要なフィールドを workspace/findings/<id>.json に追加してください。

    • ヘルパーのバージョンマーカー(必須)。 append_calibrate.py の1行目は、必ず次のコメントと完全に一致させてください。 # MANTIS_HELPER_VERSION = 2 既存のヘルパーを再利用する前に、1行目を確認してください。ファイルが存在しない場合、または1行目が # MANTIS_HELPER_VERSION = 2 と完全に一致しない場合(マーカーがない、または整数が異なる場合)は、ヘルパーを最初から再生成してください(古いヘルパーは新しい snapshot 履歴フィールドと STALE_EVIDENCE の処理を、通知なく破棄します)。再生成したヘルパーは、追加する history エントリーに snapshot キーを書き込み、sanity_triage_applied の先頭に STALE_EVIDENCE を追加できなければなりません。このヘルパーは STATE 相対です(Block A のステップ3を参照)。CODE_ROOT の下には決して書き込まないでください。

    既存の主要な検出事項データに加えて、マトリックスの内訳を示すため、次のフィールドを明示的に追加してください。

    • "impact_score"(1~5)

    • "likelihood_score"(1~5)

    • "availability_tier"(CRITICAL、STANDARD、LOW_CRITICALITY、または null)

    • "inferred_exposure"(EXPOSED、INTERNAL、または PRIVILEGED)

    • "attacker_position"(入力値を維持するか、値がない場合はフォールバック推論で設定)

    • "mantis_risk_score"(最終的な Hazard スコア)

    • "priority"(CRITICAL、HIGH、MEDIUM、LOW)

    • "sanity_triage_applied"(セミコロン区切りのリスト、または null)。順序: 検出事項が STALE の場合(前文 P4)、最初に STALE_EVIDENCE。次に Incomplete Calibration (UNKNOWN: <rule>) の警告。その後、適用された Section 3 のルールを、制約の厳しいものから順に並べます。例: "STALE_EVIDENCE; Incomplete Calibration (UNKNOWN: physical_long_term); Local Attack Vector"。

    • 27個すべての sanity cap の評価を含む "calibration_checklist" オブジェクト。このオブジェクトの各キーは、対応する名前の sanity cap ルールに対応します。

      {
        "repro_failure": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "unreachable_inputs": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "third_party_reachability": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "minor_config_hygiene": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "non_security_critical": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "vague_code_paths": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "unreliable_triggers": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "prerequisite_shell": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "physical_long_term": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "trusted_controller_zero_delta": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "standard_host_attacks": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "static_confirmation": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "strict_xss": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "internal_nested": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "probabilistic_llm": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "supply_chain_prerequisites": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "non_default_config": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "confidential_computing_host": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "trusted_controller_critical_bypass": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "local_attack_vector": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "self_contained_blast": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "rarely_exposed": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "equivalent_primitives": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "documented_insecure_config": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "physical_temporary": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "high_privilege_external": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" },
        "trusted_controller_standard_bypass": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }
      }
      

      各ルールについて、outcome は次のいずれかに設定してください。

      • "APPLIES":この指摘にサニティキャップルールが適用(発動)し、スコア/優先度を上限設定または引き下げる場合。詳細な reason 文字列が必須です。
      • "DOES_NOT_APPLY":サニティキャップルールが適用されない場合。reason フィールドは任意で、省略してトークンを節約できます。
      • "UNKNOWN":未解決の場合。詳細な reason 文字列が必須です。

      下位互換性のため、スキーマでは "fires": <bool> も使用できます(fires が true の場合に限り reason が必須です)が、新しい "outcome" 形式が推奨されます。

    • "outrage_commentary"(憤りの度合いに関する考察)

    • "executive_summary"

    • "history" 配列の項目:

      {
        "stage": "calibrate",
        "action": "calibrated",
        "details": "リスクスコアを[score]、優先度を[priority]として算出しました。[ STALE_EVIDENCE: ライブコードを再調査せずにスコアを算出しました。]",
        "pass_number": <current_pass_number>,
        "snapshot": "<active_snapshot.snapshot_id, or omit in MODE-OFF>",
        "timestamp": "<current_iso8601_timestamp>"
      }
      

各検出結果ファイルに更新内容を保存します。完了したら、ユーザーに通知してください。

コメント