


サンドボックスで、脆弱性を見つけて直すパイプラインを動かす
信頼できないコードを実際に動かしてクラッシュを探す、自動のパイプラインを運用する時に使う。実行をコンテナに閉じ込め、見つかった結果をその都度知らせ、作った修正は必ず人のレビューに回す。
このAIルールを使うには
## 読むだけの作業は分析スキルへ、コードの実行はサンドボックスへ回す
この種のシステムには性質の異なる2つの操作面があり、ユーザーを正しい方へ導く必要がある。
- インタラクティブな分析スキルはリポジトリ内のファイルを読み書きし、現在のセッション内で動く。対象コードを実行することは決してない。スコーピング、脅威モデリング、静的な脆弱性レビュー、既存の発見物の山のトリアージ、候補パッチのドラフト作成、パイプラインの別スタックへの移植にはこちらを使う。質問や読み取り専用の作業はすべてここへ通す。
- 自律パイプラインは対象を実際に実行してクラッシュを見つけ検証する。信頼できない、攻撃者に影響された可能性のあるコードを動かすため、計装済みビルドに対してサンドボックス内で実行しなければならない。ユーザーが静的な意見ではなく、実行によって検証された本物の発見結果を求めている時だけこちらへ通す。
この2つを混同しないこと——読み書き側はコードについて推論し、実行側はコードを実際に走らせる。一方は情報を与え、もう一方は証明する。実行側からの出力は文章ではなく、再現可能な入力ファイルである。
## 小さな試しの実行から始め、大きな実行はバックグラウンドで動かす
パイプラインは投げっぱなしのバッチ処理ではなく、ライブダッシュボードとして運用する。
- まずユーザーと一緒に偵察をインタラクティブに進める。発見された注目領域を見せて、何かを起動する前に分割方法を調整してもらう。
- 新しい対象への初回実行では、小さな波(並列実行数を少なく、ターン上限も低く)から始める。そうすることでユーザーはスケールアップする前にトークン消費量とプロンプト調整の感覚をつかめる。何か様子がおかしければトランスクリプトを一緒に確認する。
- その後、より大きな実行をバックグラウンドで起動し、ログを追いながら発見結果が積み上がっていく様子を見つつ、処理をブロックすることなく質問にも答えられるようにする。検証済みの結果が届くたびに、バッチ全体を待たず短い要約とともにすぐ提示する。
最初の検証済み発見は通常、数時間ではなく数分で届く。処理の遅い1件はそれ自身を遅らせるだけで、バッチ全体を止めることはない。
## 止まっても失わないよう、トランスクリプトを逐一ディスクに書く
すべての実行に、常時稼働する2つの観測レイヤーを持たせる。
- 一定ターンごとに出力されるハートビートは、長い沈黙が続く間もプロセスが生きていることを証明する。
- 各エージェントの行動を1行ずつ示す進捗ラインは、ツール呼び出しやテキストブロック1つにつき1行で何をしているかを表す。
すべてのエージェントのトランスクリプトは、メッセージが届くたびにディスクへストリーム保存し、確実にフラッシュする。重要なものをメモリだけにバッファしないため、実行途中で強制終了しても、後から確認できる完全で読み取り可能なトランスクリプトが残る。
ユーザーから状況を尋ねられたら、ディスク上の成果物から答える。まだ生きている発見の数、採点済みの数、書き出されたレポートの数を数え、最新のものを表示する。各結果はそれぞれの実行が終わった瞬間に書き出されるため、処理の遅い1件が他の結果の到着を妨げることはない。
## レート制限で止まったエージェントを、続きから再開させる
一時的な容量エラーで実行全体を潰してはいけない。長時間ジョブが突発的な負荷を乗り越えられるよう、回復のはしごを組み立てる。
- 各エージェントは1つの長寿命セッションである。実行中のレート制限やサーバーエラーは、まずエージェント自身のクライアント内でリトライされる。
- それでも解決しなければ、オーケストレーターが(上限付きの指数関数的な)バックオフを行い、そのエージェントを自分のセッションから再開する形で再起動する。これにより会話の文脈全体が復元され、失敗したまさにそのターンから続行できる。
- エージェントごとの再開回数には上限を設け、本当に詰まってしまったエージェントは最終的には停止するようにする。
ユーザーには、割り当てられた容量に近いペースで実行してよく、バックオフが突発的な負荷を吸収してくれるので、作業を失わないために自分でスロットルを絞る必要はないと伝える。1つだけ例外がある。ターン数切れのエラーは終端的なものであり、意図的に再開しない——再開するとターン上限を超えて積み重なってしまうためだ。この場合は上限を引き上げて再実行する。エージェントが上限に達する前にすでに提出していた発見は、実行と一緒に破棄されることなく回収され採点される。
## 新しいバグは自動でレポートにし、ネットワークを使う前に聞く
ストリーミングモードでは、レポート作成は自動で行われる。クラッシュが採点をクリアするたびに、判定エージェントがそれが新規のバグか、既知バグのよりきれいな代表例か、それとも見送るべき重複かを判断する。新規バグと判断されればバッチを待たずに即座にレポートエージェントが起動する。バッチ単位のレポート作成経路も、復旧用途やストリーミングなしで得られた結果のために引き続き利用できる。
各レポートは構造化された悪用可能性分析であり、そのプリミティブがどう振る舞うか、実際の攻撃対象領域から到達可能かどうか、権限拡大の経路、そして制約条件を含み、さらにエージェントが判定した深刻度も付く。別の採点エージェントが、キーワードによる走査ではなく意味的なルーブリックに照らしてそのレポートを採点する。
外部ネットワークに触れるステップ(例えば対象のアップストリームリポジトリをクローンしてバグがすでに修正済みかどうかを確認する新規性チェックなど)を有効にする前には、必ずユーザーに確認する。これはデフォルトでオフにしておく——エアギャップ環境や外部通信が制限された環境では、パイプラインが外部に手を伸ばすことを望まないためだ。ネットワークに触れるのはオーケストレーターのホストのみであり、エージェントのコンテナはどちらの場合もモデルのエンドポイントだけに制限されたままにする。
## パッチでクラッシュが消えたかを確かめ、採用は人に任せる
パッチ適用フェーズは、レポート作成の後に実行することも、単独で実行することもできる。それぞれのユニークなクラッシュについて、まっさらなサンドボックスコンテナ内のパッチエージョントが修正を書いてdiffを出力し、別の採点コンテナが検証のはしごを一段ずつ確認していく。
- diffを適用してリビルドする。
- 元の再現用入力がもうクラッシュを引き起こさないことを確認する。
- 対象自身のテストスイートが依然としてパスすることを確認する。
- パッチ済みバイナリに対して、まっさらな時間制限付きの発見エージェントで再攻撃する。
いずれかの段階で失敗した場合、その証拠がフィードバックされ、パッチエージェントは上限回数まで反復する。最終段として、任意でアドバイザリー形式のレビューを追加することもできる。
このはしごが何を証明しているのかをユーザーに明確に伝える。このはしごが検証するのはクラッシュが消えたことであり、そのdiffがアップストリームに取り込んで安全であることまでは検証しない。diffは人間によるレビューのために提示し、レビューのガイドラインを示す。パイプライン自身のコンテナの外にあるものへdiffを適用すると申し出てはいけない——生成された修正は人間が採用を判断するための提案であって、自動的に反映される変更ではない。
## 同じクラッシュかどうかは、文字ではなく原因でエージェントに判断させる
クラッシュの重複排除は、文字列一致ではなく2つの層でのエージェントの判断によって行う。
- 提出時点で、発見エージェントは、そのクラッシュが共有の発見ファイルにすでに記録されているものと何が違うのかについて、自身の推論を必ず添付しなければならない。それを欠く提出はパイプラインが拒否する。判断を下すのはそのバグの根本原因を知っているエージェント自身であり、パイプラインはその判断が実際になされたことを強制するだけである。生のサニタイザー出力の抜粋との比較は、完全一致ではなく意味的に行う。
- レポート作成のゲートでは、判定エージェントが採点済みの各クラッシュを、現在稼働中のレポート一覧と照らし合わせて読み、新規・よりきれいな重複・見送りのいずれかを判断する。同じ根本原因が異なる行やフレームで表面化した場合でも重複と見なされる。よりきれいな重複と判断された場合は再レポートが発生し、その後の比較ステップで正典となる方を選ぶ。
既知のバグを記録する際は、行番号ではなく関数名をキーにする。同じバグでも、入力によって隣接する行でクラッシュしたり、異なるサニタイザーの種類として現れたりするためだ。
## 発見と採点を、制限をかけた別々のコンテナで動かす
この隔離モデルこそが、実行によって検証された結果を信頼できるものにしている。交渉の余地のないものとして扱う。
- 発見(find)と採点(grade)は、同じイメージからビルドされた別々のコンテナで実行する。両者の間を越えるのは概念実証(PoC)のバイトデータのみである。発見側は採点側に一切触れることがなく、これによって事前に仕込まれた状態を利用した報酬ハッキングを防ぐ。
- 各エージェントは、強化されたランタイムを持つ自分専用のコンテナ内で動作し、外向き通信は設定済みの許可リストに制限される——これはホスト上ではなくサンドボックス内で行われる。そのファイル操作とシェルツールは、そのコンテナ内に閉じ込められる。
- エージェントを起動するコマンドは、明示的な危険オーバーライドが渡されない限り、サンドボックスの外では起動を拒否する。
- エージェントが使えるツールセットは固定かつ最小限である。実行を担うエージェントは読み取り・書き込み・シェルのみを持ち、判定エージェントと比較エージェントはツールを一切持たず、すべてを単一のプロンプト呼び出しの中で行う。プラグインツールもウェブアクセスもない。
## 起動を壊す設定に気をつけ、対象はコードを変えずに足す
崩れやすく、あらかじめ知っておく価値のある運用上の細部がいくつかある。
- 一部の環境設定は運用を支える土台になっている。あるものはコンテナ内ツールのネストセッションガードを無効化し、別のものはサンドボックス内で権限バイパスモードを受け入れられるようにする。どちらかを外すとエージェントの起動が壊れる。
- 「使えるツールセットを制限する」と「権限の許可リスト」は区別すること——あるCLIは両方のフラグを受け付けるが意味は異なる。単に許可されているかどうかではなく、実際にどのツールが存在するかを絞り込む方を使う。
- モデルの選択は静的な設定ではなく実行時の引数であるため、同じ対象定義を任意のモデルで動かすことができる。
- サニタイザーで計装されたパーサーには、コンパイラのインライン化によってクラッシュのシグネチャが変わってしまわないよう、no-inline属性が必要になる場合がある。
対象を追加するのは、ビルド定義とサニタイザー設定を備えたディレクトリを1つ置くだけのドロップイン作業であり、パイプライン本体のコード変更は不要である。タグと出力の解析、成果物のシリアライズ、シグネチャ抽出、重複排除、パッチ採点のはしごといった可動部分はユニットテストでカバーし、エンドツーエンドのスモークパスとして軽量な固定対象を1つ維持しておく。
## ログに残った攻撃の跡を、答えが見えないコンテナで探す
侵入後を扱う姉妹版は問題設定を反転させる。攻撃者はすでにログの中に存在しており、仕事はバイナリをクラッシュさせることではなく、その攻撃キャンペーンを見つけ出すことになる。
- ログのコーパスは、何かを実行する前にあらかじめ生成しておかなければならない。これはサイズが大きく、シードごとに決定論的なので、同じマシン上では同じシードから同じ証拠が再現される。
- 探索エージェントはアプリケーションのソースコードと読み取り専用のログを与えられ、インシデントの発見結果を提出する。設計上、そのコンテナの中には答えとなる情報は一切存在しない。
- まっさらなコンテナ内の採点エージェントが提出物を採点し、確認済みの概念実証(PoC)をすべて独立に再実行して検証する。境界を越えるのは提出物のみである。
評価の完全性を守ること——正解データのファイル、採点者、ログ生成器のソースコードはすべてネタバレになる。探索側でそれらをマウントしたり読み取ったりしてはならない。クラッシュ発見パイプラインと同じ、インタラクティブから自律への流れがここにも当てはまる。
