検出結果だけでなくエビデンスを生み出すAIペンテストのプロンプト
構造化された出力、検証ゲート、制御された実行を通じて、スコープを限定したエビデンスをレビュー可能な検出結果へと変える、AI支援型セキュリティテストのワークフロー設計に関する実践ガイドです。
モデルに脆弱性の発見を依頼する
新しいAPIが手元に回ってきたと想像してください。数十のルート、見慣れないミドルウェア、そしてレビュー担当者が何日もかかりきりになるほどの量のコードが含まれています。
モデルに与えたプロンプト:「このリポジトリをレビューして、セキュリティ上の脆弱性を見つけてください。」
少しすると回答が返ってきます。SQLインジェクション、ハードコードされたシークレット、認可チェックの欠如、安全でないデシリアライゼーションが挙げられています。内容は整理されていて自信に満ち、セキュリティレポートのような体裁に整えられています。
判断ポイント:これをエンジニアリングチームに送るでしょうか。
まだ送るべきではありません。まず、モデルが実際に何をテストしたのかを確認します。もしかすると、リクエストからデータベースまで追跡されたエンドポイントは一つもないかもしれません。危険なシンクに到達した入力もありません。認可の判定が実際に試されたわけでもありません。悪用可能性の条件が確認されたわけでもありません。出力には有用な仮説が含まれている可能性がありますが、仮説はまだ検出結果ではありません。
AI支援型のセキュリティテストが役に立つものになるか、単なるノイズになるかは、ここで分かれます。課題は、モデルをペンテスターらしく語らせることではありません。漠然とした依頼から絞り込んだ問いへ、その問いからエビデンスへ、そしてエビデンスから他のエンジニアが再現できる結果へと進めることです。
判断を一つずつ積み重ねながら、このテストを組み立て直してみましょう。
まず、答える価値のある問いを一つ選ぶ
生成された手がかりの中には、GET /v1/invoices/{id}に認可の問題があるかもしれないというものが含まれています。
当初の主張:「このエンドポイントは、他のユーザーに属する請求書を露出させる可能性がある。」
必要なエビデンス:リソースの所有者を特定し、認可制御の場所を突き止め、攻撃者が持つアクセス権を把握したうえで、認証済みのあるユーザーが別アカウントの請求書をリクエストしたときに何が起きるかを観察します。
テストの目的:認証済みユーザーがGET /v1/invoices/{id}を通じて、別アカウントが所有する請求書を取得できるかどうかを判定します。
対象は小さくなりましたが、調査はより深くなりました。調査には今や、インターフェース、所有権の境界、攻撃者の能力、そして成功条件が備わっています。
同じ転換は、セキュリティのさまざまな領域で有効です。
| 漠然とした依頼 | ワークフローが答えられる問い |
|---|---|
| Androidのインテントを確認する | エクスポートされたアクティビティShareActivityについて、攻撃者が制御するエクストラが検証を経ずに特権コンポーネントへ到達できるか。 |
| インジェクションを探す | sortクエリパラメータが、安全な処理を経ずに動的なクエリ操作へ到達できるか。 |
| 保存されたシークレットを探す | 機密と疑われる値がアプリケーションのストレージに書き込まれているか。また、明示した攻撃者モデルのもとでそれを復元できるか。 |
これがコンテキスト分離の実践です。リポジトリ全体をモデルに丸ごと渡すのではなく、ルート定義、関連するミドルウェア、ハンドラー、データアクセスコード、テスト、そして観測したリクエストやレスポンスのエビデンスを提供します。
これでモデルが読み回る材料は少なくなり、答えるべき明確な問いが一つに定まりました。
次に、何をもって実証とするかを決める
モデルが請求書のハンドラーを読み、次のように返したとします。
当初の主張:「このエンドポイントはIDで請求書を取得しているため、安全でないオブジェクト直接参照(IDOR)に対して脆弱である。」
判定:まだ結論は出せません。IDでオブジェクトを取得するのは、アプリケーションとしてごく普通の動作です。決め手となる問いは、レスポンスが返される前に、所有権のチェックや別の認可ポリシーが適用されているかどうかです。その制御は、ミドルウェア、サービス層、データベースクエリ、あるいは見えている範囲の外にあるポリシー関数に存在する可能性があります。
結論を求める前に、タスクにエビデンス契約(evidence contract)を与えます。ワークフローには、調査したコードパス、攻撃者の能力、想定される認可制御、検証用のリクエストとレスポンス、そしてconfirmed、needs_validation、not_reproducedのいずれかのステータスを返すよう求めます。
構造化された出力によって、主張が正しくなるわけではありません。実証が欠けていることを目に見えるようにするのです。
task:
id: api-object-authorization-001
vulnerability_class: broken_object_level_authorization
target:
method: GET
path: /v1/invoices/{id}
owner_boundary: account_id
objective: >
Determine whether an authenticated user can retrieve an invoice that belongs
to a different account.
permitted_actions:
- Read source files listed in context.
- Inspect supplied test traffic and test fixtures.
- Generate a test request only against the approved staging target.
required_evidence:
- Authorization check location or its absence.
- Request and response identifiers for the cross-account test.
- Expected versus observed authorization result.
output_rules:
- Do not report a confirmed vulnerability without runtime or test evidence.
- Return needs_validation when execution is unavailable.
- Cite every conclusion with an evidence reference.
この契約によって、プロンプトをどう改訂しても維持すべきルールが一つ導入されます。
エビデンスなくして確定なし。
続いて、各結果に次の一手を選ばせる
モデルはルートを追跡します。認証ミドルウェアと、識別子で請求書を読み込むデータベースクエリは見つかりました。しかし、所有権の条件はまだ見つかりません。
次の判断:新たな説明を生成させるのではありません。不確実性を減らせる次のテストを選びます。ワークフローには、制御されたループが必要です。
- 計画:不確実性を減らせる最小の問いを特定します。
- 収集:関連するソースコード、フィクスチャ、トラフィック、または承認済みツールの出力を取得します。
- 分析:エビデンスを、レビュー対象のセキュリティ制御と結び付けます。
- 検証:リクエストを再送する、安全なテストを実行する、トレースを調べる、あるいは人間によるレビューを依頼します。
- 判断:検出結果を確定するか、仮説を絞り込むか、あるいは調査を打ち切ります。
請求書エンドポイントについては、テスターが管理するステージング環境のアカウントを2つ使用します。アカウントAで、一意かつ機密性のないマーカーを含む請求書を作成します。まず、テスト対象のエンドポイントを通じてアカウントAがその請求書を取得できることを確認します。次にアカウントBとして認証し、同じ識別子をリクエストします。
検証の問い:どのような結果が得られれば、問題を実証したことになるでしょうか。
アカウントBがアカウントAの一意なマーカーを受け取った場合、このテストはアカウントをまたいだアクセスを実証したことになります。ただしそれは、請求書が非公開であり、両アカウントの間に共有関係がない場合に限られます。アクセスが拒否された場合は、テスト対象の経路がこのケースにおいて境界を適用していたことを示します。ベースラインがない、レスポンスが不明瞭である、共有が意図されたものである、あるいはテスト環境が利用できない場合、結果はneeds_validationのままです。
ソースコードのトレースと実行時のレスポンスは、それぞれ異なる問いに答えます。前者は、制御が欠けているように見える箇所を示します。後者は、稼働中のシステムが実際にどう振る舞うかを示します。信頼できるワークフローは両方を保持し、一方を他方で代用することは決してありません。
ループを回すたびに、調査の状態が変化しなければなりません。同じ疑いを言い換えたものしか生み出さないのであれば、そのシステムは対象をテストしているのではなく、言葉を生成しているにすぎません。
同じ手法をほかのセキュリティ上の問いにも適用する
請求書のケースでは一つの完結した道筋が得られましたが、AIペンテストのワークフローを認可だけを軸に設計することはできません。同じ考え方を、3つの異なる調査に当てはめてみましょう。
Androidのインテントは出発点にすぎない
モデルが、ShareActivityという名前のエクスポートされたAndroidアクティビティを見つけます。あわせて、受信したインテントのエクストラとstartActivityの呼び出しも確認します。
判断ポイント:これだけで、インテントリダイレクションとして報告するのに十分でしょうか。
十分ではありません。ワークフローは、まだ個々の要素をつなぎ合わせる必要があります。コンポーネントが外部から到達可能であることを確認し、攻撃者がどのエクストラを制御できるかを特定し、それらの値がstartActivity、startService、sendBroadcastに至るまでを追跡し、呼び出しの前に適用される検証やコンポーネントの制限を調べるべきです。
次のステップは、別のアプリケーションから行う、制御された実行時テストです。インテントリダイレクションを確定するには、細工した入力によって、テスト用アプリケーションからは直接呼び出せない動作を被害者側のアプリケーションに実行させる必要があります。たとえば、エクスポートされていない内部コンポーネントや、保護された操作に到達するといったケースです。
別のエクスポート済みアクティビティを開けたとしても、セキュリティの回避を実証したことにはなりません。入口となるアクティビティがエクスポートされていない、ネストされたインテントが制限されている、あるいは保護された効果が何も生じない場合は、主張を絞り込むか、not_reproducedとします。
危険なAPIは手がかりにすぎませんでした。それが検出結果になるかどうかを決めるのは、到達可能性、攻撃者による制御、そして観測された動作です。
クエリパラメータがそのままインジェクションになるわけではない
次に、モデルはsortクエリパラメータがクエリ構築関数に到達していることに気づき、その経路に「SQLインジェクションの可能性」というラベルを付けます。
次の問い:その値はSQLコマンドの一部になるのでしょうか。それともデータのままでしょうか。nameやcreated_atを固定のカラム名に対応付ける許可リストがあれば、結論は変わります。値がクエリに直接挿入されているのであれば、承認された環境で安全な検証テストを行う根拠になります。
ワークフローは、HTTPハンドラーからクエリビルダーまで値を追跡し、検証や変換があればそれを記録します。続いて、テスターが所有するデータに対して、対になる非破壊的なテストを実行します。インジェクションを確定するには、ベースラインのリクエストが安定したまま、攻撃者が制御する入力によってクエリの動作が変化する必要があります。データベースエラーだけでは不十分です。不正な形式の入力は、インジェクションを可能にしなくてもエラーを引き起こすことがあるからです。攻撃者の入力が到達しない文字列連結は静的なエビデンスにとどまり、悪用が実証されたことにはなりません。
機密性の高い値は実際にストレージへ到達していなければならない
最後に、モデルはSharedPreferences、ローカルデータベース、またはキャッシュに値を書き込むコードを見つけ、「機密データが安全でない方法で保存されている」と報告します。
欠けているエビデンス:ワークフローは、まずその値を特定しなければなりません。ストレージAPIがあるからといって、パスワード、トークン、個人データ、暗号鍵素材がそれを通じて書き込まれていることにはなりません。そのうえで、書き込み経路を追跡するか、該当するアプリケーションのフローを実際に動かし、明示した攻撃者モデルのもとで、結果として生じたストレージの内容を調べる必要があります。
テスターが所有する機密性の高い値がディスク上に現れた場合は、その保存場所、作成手順、保護の状態、復元の条件を記録します。また、抽出にデバッグ可能なビルド、run-as、バックアップへのアクセス、root権限、物理アクセス、実行時インストルメンテーションのいずれが必要だったかも明記します。
root権限を取得して初めてプライベートストレージから復元できたデータは、外部から読み取り可能なストレージで露出しているデータと同じリスクの主張を裏付けるものではありません。エビデンスが汎用的なストレージヘルパーの存在しか示していない場合、その主張は仮説のままです。
これらの例では、使うツールもエビデンスも異なりますが、たどる流れは同じです。問いを絞り込み、攻撃者による制御を追跡し、想定される制御を特定し、安全にテストし、観測された結果を保存するという流れです。
手がかりは検証ゲートで検出結果になる
アカウントAは、マーカーを付けた自分の請求書を正常に取得します。続いて、共有関係のないアカウントBが、同じエンドポイントを通じて同じ非公開のマーカーを取得します。ワークフローは、両アカウントのアイデンティティ、所有権のベースライン、リクエスト、レスポンス、コードパス、そして観測されたアカウント間の情報開示を記録します。
ここに至って初めて、手がかりは確定した検出結果になり得ます。
主張が異なれば、必要なゲートも異なります。
| 主張 | ワークフローが実証しなければならないこと |
|---|---|
| 機密性の高い値がローカルに保存されている | 明示した保存場所からテスターが所有する値を復元し、アクセスの前提条件を文書化します。 |
| エンドポイントにオブジェクト単位の認可が欠けている | 所有者によるアクセスを確認したうえで、共有関係のない、テスターが管理する2つ目のプリンシパルによるアクセスを実証します。 |
| ユーザー入力が危険なシンクに到達する | 攻撃者による制御を追跡し、対になる安全なテストによって、そのシンクのセキュリティ上重要な動作を実証します。 |
| リモートコード実行 | 許可された環境で、一意かつ無害な実行マーカーを生成します。クラッシュだけでは不十分です。 |
疑わしいAPI、欠けているように見えるチェック、見慣れないエンドポイント、危険な関数は、次のテストの指針にはなります。しかし、どれもそれだけで報告に値する脆弱性になるわけではありません。
検証ができない場合:そのことを明記します。Needs_validationは、何が未解明のまま残っているかをレビュー担当者に伝えるため、自信満々の誤検知(フォールスポジティブ)よりも有用です。
モデルにツールを与える前に、境界を定める
調査がうまく進んでいると、モデルにより多くのアクセス権を与えたくなります。ツールを増やし、対象を増やし、場合によっては本番環境の認証情報まで渡したくなるかもしれません。
安全性の問い:このワークフローがタスクを誤解したり、悪意のあるコンテンツに従ったりした場合、取り得る最も被害の大きい行動は何でしょうか。
「注意してください」はセキュリティ境界ではありません。実行レイヤーで、ソースコードへの読み取り専用アクセス、許可リストに登録された対象、合成アイデンティティ、レート制限、承認済みのステージング環境、そして状態を変更する操作の前の人間による承認を強制しなければなりません。
リポジトリ内のファイル、チケット、Webページ、ログ、対象からのレスポンスは、信頼できない入力です。そこには、AIシステムの向かう先を変えることを意図した指示が含まれている可能性があります。したがって、プロンプトインジェクションや過剰な自律性はシステム設計上のリスクであり、巧みな言い回しだけで解決できる問題ではありません。
モデルは行動を提案することはできます。それが許可されるかどうかを決めるのは、実行レイヤーです。
一度成功したテストも、一つのテストにすぎない
信頼性の問い:請求書の調査が一度成功したことで、プロンプトのアーキテクチャが信頼できると証明されたことになるでしょうか。
なりません。証明されたのは、一つのワークフローが一つのケースに対処できたということだけです。
確定した脆弱性、既知の誤検知、問題のないコンポーネント、そして正しい結果がneeds_validationとなる不完全なケースから、評価セットを構築します。モデル、プロンプト、ツール、コンテキスト選択のルール、出力スキーマのいずれかが変更されるたびに、それらのケースを実行します。
そのうえで、次のことを確認します。
- 既知の問題を特定できたか。
- 正しいエビデンスを添付したか。
- 既知の誤検知を棄却したか。
- 実行時の実証が得られないときに停止したか。
- レビュー担当者が結論を再現できたか。
これにより、プロンプトの編集はエンジニアリングになります。変更が採用に値するのは、計測された成果を改善したときであり、より説得力のある文章を生み出したときではありません。
今なら何を信頼するか
最初の回答に戻りましょう。漠然としたリポジトリのレビューから生成された、脆弱性の可能性を洗練された体裁で並べたリストです。
これを請求書の調査と比べてみてください。後者の結果には、範囲が限定された対象、攻撃者モデル、コードのトレース、管理された2つのアイデンティティ、記録されたリクエストとレスポンス、観測された認可の不備、そして定義済みの検証ゲートを通過したステータスがそろっています。
最終判断:エンジニアリングチームに送るのは、どちらの結果でしょうか。
AIは、セキュリティチームが大規模なコードベースを読み進め、エビデンスを整理し、焦点を絞ったテスト計画を作成し、次に何を調べるべきかを判断するのを支援できます。しかし、対象、テスト、制御、レビュー担当者が不要になるわけではありません。
目指すべきは、脆弱性の可能性をより長く並べたリストではありません。対象を貫く、短く、根拠を示せる道筋です。
スコープ → 問い → エビデンス → テスト → 観測結果 → 結論。
それこそが、セキュリティテストについて説明できるモデルと、他のエンジニアが再現し、異議を唱え、修正し、検証できるものを残すワークフローとの違いです。