AIニュース最前線
最新ニュースAI日報Hacker日報週報動画AIツールトレンド企業

AIニュース最前線

世界中のAI最新情報を日本語で毎時更新

最新ニュース日報トレンド企業プレミアムRSS
© 2026 ainew.jp特定商取引法に基づく表記
ニュース一覧元記事を開く
Cloudflare Blog·2026年6月19日 02:59·約25分で読める

独自の脆弱性ハーンを構築する

#LLM#Security AI#Agentic Workflows#Model Agnostic#Cloudflare
TL;DR

Cloudflare は、単一モデルへの依存を避けるため、複数の AI モデルを相互交換可能かつ横断的に検証する「脆弱性ハネス」の構築手法と、そのアーキテクチャ設計について詳述している。

AI深層分析2026年6月19日 04:03
4
重要/ 5段階
深度40%
5
関連度30%
5
実用性20%
4
革新性10%
4

キーポイント

1

単一モデル依存の限界とリスク

特定のモデルに依存すると、同じコードパスを同一の視点でしか分析できず、防御カバレッジが制限されるため、モデルの頻繁な交換とクロステストが必要である。

2

ハネス型アーキテクチャの必要性

サブエージェントやプロンプトだけでは不十分であり、数百もの調査を継続的に維持・重複排除・再スコーピングするオーケストレーション機能を持つ専用ハネスが不可欠である。

3

モデル非依存な検証パイプライン

初期発見と検証に異なるモデルを使用するなど、多様なロジックで脆弱性をクロスチェックし、単一レポジトリを超えた依存関係の追跡を行うことで信頼性の高い修復キューを生成する。

4

実装における課題と解決策

状態管理の制御、誤検知(False Positives)の排除、および大規模なトリアージの調整といった、実用的なハネス構築のための具体的な技術的アプローチを提示している。

5

モデル非依存なハネス設計の重要性

脆弱性発見において重要なのは特定のモデルではなく、システム自体であるため、最初からモデルに依存しない設計を行うことで、どの最新モデルでも自由に利用可能にする必要がある。

6

7段階のセキュリティ監査プロセス

リコン、ハンターによる攻撃試行、検証者による反証、報告書作成、JSON形式での出力、機械的チェック、独立した再検証という7つのフェーズで構成される自動化された監査フローが確立されている。

7

単一実行の限界とアーキテクチャの課題

単一のセッションでは発見できるバグの半分程度しか見つからない上に、文脈の飽和や予期せぬクラッシュによる作業喪失を防ぐため、状態を外部化し堅牢なハネスへの移行が必要となる。

影響分析・編集コメントを表示

影響分析

この記事は、AI を活用したセキュリティ対策における「モデル依存症」という根本的な課題を指摘し、より堅牢なシステムアーキテクチャへの転換を促す重要な示唆を与えています。単なるツールの紹介ではなく、大規模かつ継続的な脆弱性管理を実現するための設計原則(オーケストレーション、状態管理、クロス検証)を提示しているため、セキュリティエンジニアや AI 運用担当者が自社のインフラを再構築する際の指針となるでしょう。

編集コメント

単一モデルの性能競争に終始する業界に対し、多様なモデルを組み合わせる「ハネス」アプローチの重要性を説く、非常に示唆に富む技術記事です。実運用におけるスケーラビリティと信頼性を確保するための具体的な設計思想が得られます。

数週間前、私たちはプロジェクト・グラスウィングの初期調査結果を発表しました。これは、最先端のセキュリティモデルをエンタープライズコードベースに適用した場合に何が起こるかを分析したものです。また、最先端 AI によって引き起こされる脅威からインフラストラクチャと顧客を守るために、私たちの防御構造がどのように適応するかについても探求しました。それ以来、AI エコシステムは急速に変化し続けています。単一のモデルの周りに緊密に構築してきた開発者たちは、そのモデルが使えなくなった場合や、より能力の高いモデルに置き換わった場合に何が起こるかをすでに経験しています。これらの市場の変化は、私たちの核心的な仮説をさらに裏付けています。つまり、どの基礎となるモデルがその日のトップを走っているかに関わらず、エージェント型ワークフローの未来は、スタンドアロンのモデルやプロンプト、あるいは単一のエージェントセッションには見出せないのです。

ローカライズされたセキュリティ「スキル」から、継続的で艦隊全体のスキャンパイプラインへ移行するには、モデルを交換可能なコンポーネントとして扱うアーキテクチャが必要です。単一のモデルに依存することは本質的に防御のカバレッジを制限します。なぜなら、同じシステムはコードパスを全く同じレンズを通して見てしまう傾向があるからです。これに対抗するため、モデルは頻繁に交換され、相互テストされるべきです。パイプライン全体でモデルを変化させること(例えば、初期発見には一つのモデルを使用し、検証には全く異なるモデルを使用するなど)により、脆弱性が論理の異なるセットによってクロスチェックされることを保証できます。さらに、真のエントプライズスケールのハーンネスは、孤立したリポジトリを超えて、リポジトリ間の依存関係にわたる脆弱性を追跡し、最終的に数千もの生のカンディデートを、信頼できるトリアージ済みキューのアクション可能な修正へと絞り込む必要があります。

本記事では、状態制御の管理方法、偽陽性の排除方法、そして大規模なエンドツーエンドのトリアージ調整方法を焦点に当て、このモデル非依存レイヤーをどのように構築するかを実践的な視点から解説します。

二つの異議、冒頭で

最初の投稿では、汎用的なコーディングエージェントがこのタスクを遂行できない理由について論じました。主な問題は、エージェントが一度に一つの仮説しか保持できず、実際のリポジトリのごく一部をカバーした後にコンテキストウィンドウを満たし、その後コンテキスト圧縮の過程で情報を失ってしまう点にあります。詳細は当該記事をご覧ください。

進む前に、おそらく来る二つの質問にお答えしたいと思います。

"なぜハーンではなくサブエージェントを使うのですか?" サブエージェントは有用であり、良い出発点です。しかし、セキュリティ分析には、実行を跨いで存続し、コンテキストウィンドウを共有せず、後でスコープを再定義したり相互参照したりできる数百の別々の調査が必要です。そこには永続性、重複排除、再開可能性、そして最終的には組織全体にわたる依存関係追跡が必要となります。これはオーケストレーションの問題であり、プロンプトだけでこれを実現することはできません。

"このブログ記事はフロンティアモデルのための広告ではありませんか?" いいえ。私たちのアプローチの中心はハーンにあり、モデルにはありません。脆弱性発見に関しては、私たちが求めていることに現在最も適しているフロンティアモデルを何でも使用して実行します。異なるモデルを同じターゲットに向けると、それぞれが異なる割合のバグを特定します。残る部分はハーンです。もし独自のシステムを構築するなら、初日からモデル非依存として設計してください。これにより、制約なく任意の選択したモデルを使用する自由が得られます。

すべてはスキルから始まる

私たちは、単一のリポジトリで実行し、実際のバグを表面化させるまでプロンプトを調整した、約 450 行のセキュリティ監査スキル(security-audit skill)から始めました。その後、システム全体の配管となったオーケストレーションを追加しました。真の価値はプロンプト自体にあり、私たちのプロンプトは依然として初期スキルの攻撃者シナリオ、バグクラス、およびアンチパターン検出をほぼ変更せずに引き継いでいます。

このスキルは、1 つのセッションで 7 フェーズの監査(audit)を実行するように記述されています:

3 つの並列する研究エージェントが情報収集を行い、architecture.md を作成します。

各攻撃クラスごとに 1 つの Hunter エージェントが実行され、コードをレビューするのではなく、それを破ろうと試みます。

敵対的なバリデータは、それぞれの発見を否定しようと試みます。

生き残ったものは人間が読みやすい脆弱性レポートとして記述されます。

また、それらは findings.json としてスキーマに対して出力され、機械的なチェックによってそのファイルが検証されます。

最後に、新しいエージェントが独立してソースコードに対してすべての発見を再検証します。

生存し、再検証された発見は ingest API に提出されます。

この最初のスキルは、後のハネスとほぼ直接対応しています:

スキルフェーズ

ハネスステージ

情報収集エージェントが architecture.md を作成

情報収集

ハンターが各攻撃クラスごとに実行される

探索

バリデータが発見を否定する

検証

生存した発見がレポートとなる

レポート

findings.json は整合性の正しさではなく、スキーマへの適合性について機械的にチェックされる

findings 内の行番号と関数の機械的検証

新しいエージェントが発見を再検証する

独立検証

このスキルは機能しましたが、すぐにその限界が明らかになりました。カバレッジ指標を見ると、単一のランでは、複数回実行して検出できるバグの約半分しか見つかりません。私たちの経験則では、発見されたものは単純で微妙さの少ないものへと偏っていました。プロセスが基本的に「10 回実行して手動で差分を取る」状態になってしまったら、本格的なハネスを検討し始める必要があるでしょう。

スキルを実行・微調整している間、私たちは 3 つの壁に直面しました:

コンテキストの枯渇:1 時間経過するとコンテキストウィンドウがいっぱいになり、モデルは自身のメモリを共食いしてしまい、朝から追跡していたバグを即座に忘却します。このボトルネックを打破するために、状態を完全に外部化し、LLM をステートレスな計算エンジンとして扱いました。

永続性:実行中にクラッシュすると最初からやり直しになります。AI のレート制限エラーや接続の不安定さによって数時間の作業が失われることは、より良いアーキテクチャが必要だと気づくための非常に高価な方法です。

跨リポジトリ推論:単一のリポジトリセッションは、それを利用するアプリケーション間の関係を完全に把握できず、コンポーネント間のインターフェースを検査した際に表面化するバグの数は、予想以上に多い可能性があります。

助言:真に必要最小限のハーン(harness)とは、Recon、Hunt、Validate の各ステージをデータベースに保持し、独自の発見事項を提出できない別個の Validator を用意するものです。重要なリポジトリが 1 つを超えるまで、跨リポジトリの追跡は完全にスキップしてください。ノイズで溺れていると実感するまで、専用の重複排除(Deduplication)エージェントもスキップしてください。まずは開発環境内でスキルを習得し、プロンプトがうまく機能するようにしてから、それが特定のボトルネックとなっている場合にのみ次のアーキテクチャステージを構築してください。

スキルをパイプラインとして定式化

この分野におけるほとんどの AI セキュリティに関する記事は、単一のリポジトリや厳選されたベンチマークについてのものであり、クロスリポジトリ追跡を伴うような大規模なフリート全体をこのような方法で実行する事例が他で見られることはほとんどありません。私たちのコードベースは、Rust、Go、C、Lua、TypeScript、Python といった多様な言語に加え、さまざまな構成管理システムや静的設定ファイル、そしてあらゆる種類の追加コンテキストにまたがる巨大な混合体です。そのため、私たちにとって機能する新しいアプローチを考案する必要がありました。最初のスラッシュコマンド実行から、128 の異なるリポジトリをカバーし、関連する依存関係を自動的に発見・調査できるフリートスキャナへと移行するには約 6 週間かかりました。コード化の大部分は機械的な作業でした:スキルの各フェーズを個別のエージェントに昇格させ、その背後にデータベースを配置し、前面にはオーケストレーターを設置しました。マッピングはほぼ 1 対 1 でした。

フリート全体は、言語ごとの調整を必要としない単一の統合されたハーンネス(harness)上で稼働しており、リポジトリ間の依存関係を追跡します。構文解析をモデルに任せることでシステムが言語非依存となる一方で、その決定的な差別化要因はリポジトリ間の依存関係を追跡できる能力です。このハーンネス自体は、C のポインタを対象としているのか TypeScript ファイルを対象としているのかには関心を持ちません。セキュリティオーケストレーションのより高レベルなロジックに焦点を当てています。これにより、カスタムの言語パーサーを書くことなく、数百もの異なるコードベースにわたってスケーリングすることが可能になります。

二段階の脆弱性調査ワークフロー

私たちの脆弱性調査ワークフロー全体は、脆弱性発見ハーン (VDH) と脆弱性検証システム (VVS) という 2 つの段階からなる運用フレームワークの上に構築されています。

VDH は発見エンジンとして機能し、コードベースを能動的にスキャンして潜在的なセキュリティ課題を浮き彫りにします。バグが VVS に流入すると、複数のハーンからデータを受け取るこのシステム内で、重複排除 (Deduplication)、判定 (Judgment)、そして最終的な修正 (Fixing) の各段階を経て処理されます。これらについては後ほど詳しく説明します。

VDH には 1 つのモデルを使用しますが、VVS には全く異なる別のモデルを採用しています。つまり、両方のモデルが互いに二重チェックを行う仕組みです。これには明白なセキュリティ上の利点があります。モデル B (VVS) にモデル A (VDH) の出力を判定させることで、発見された事象が、論理的な重み付けとトレーニングデータが全く異なるセットによって評価されることを保証できます。これは、モデル A の仮定を容赦なくストレステストする唯一の役割を持つ、偏りのない敵対的な第三者として機能します。運用面では、モデルプロバイダーを相互交換可能な商品のように扱うことで恩恵を受けます。モデルプロバイダーは、時間とともに温度設定やキャッシュ戦略、推論処理のリソース予算を変更できるためです。モデルが時間経過の中で予測可能に動作することに依存するシステムを構築するのではなく、私たちのハーンは下流の振動を検知しても破綻しないように設計されています。

第 1 ステージ:脆弱性発見ハーン (VDH)

最初の投稿では各エージェント/ステージの役割について解説しましたので、今回はそれ以外の部分、つまりステージ間の接着剤や、システムが機能するかどうかを決定するいくつかの詳細についてお話しします。

エージェント/ステージ

主な役割

サブエージェント/ツール

Recon(偵察)

ターゲットアーキテクチャのマッピングと潜在的な脅威ベクトルの特定

3 つの並列実行される Recon サブエージェントが architecture.md を作成

Hunt(狩猟)

クラス別攻撃の実行、断片の統合、バイナリのプロービング

兄弟プロセスを起動します(これらはモデルに応じて fleet 全体のタスクの 9% から 20% を処理します)。また、Wishlist ツールにアクセスして書き込みを行います。

Validate(検証)

発見事項を機械的にチェックし、その後敵対的な手法でその妥当性を否定する

2 つのパスで実行されます。最初のスキーマ/パスチェックは通常のコードが担当し、報告前に発見事項の否定を試みる単一の孤立したエージェントが後続します。

Gapfill(ギャップ補充)

未カバー領域に対する新たな狩猟タスクを生成

まだ薄くテストされている可能性のある (エリア × 攻撃クラス) のセルに対して、新鮮な狩猟タスクをキューに追加

Dedup(重複排除)

重複する発見事項の特定と統合

決定論的コードとエージェントを組み合わせて、根本原因に基づいて発見事項をクラスタリングし、リアルタイムで統合します。

Trace(追跡)

依存関係グラフの探索とコンシューマーリポジトリタスクの起動

グラフをたどり、特定されたすべてのコンシューマーリポジトリ内に狩猟タスクを追加し、リポジトリ間バグが検出されるようにします。

Feedback(フィードバック)

既存レポートから学習し、今後の実行を最適化

検証の失敗、浅い実行、および繰り返されるミスを取得し、キューされたプロンプトを即座に書き換えて、将来のタスクをより鋭くします。

レポート

人間が読みやすい形式でレポートを生成します。

単なるスクリプトであり、モデルは不要です。

表 1: 脆弱性発見ハーンネス (VDH)

ステージ 4 から 8 は、継続的なプロデューサー・コンシューマーループとして実行されます。初期の探索が進行するにつれ、Gapfill(ギャップフィリング)、Feedback(フィードバック)、Trace(トレース)エージェントが新しいタスクを生成し、Dedup(重複排除)は重複した発見結果を統合し、残りのループ部分はキューを引き続き消費します。これにより、サイクルの遅い段階で発見された脆弱性であっても、同じ実行内で検証され、報告され、他のコードと比較されて同一のバグが含まれていないことが確認されます。

パイプラインをこのように分割することで、厳格なコンテキスト制御が保証されます。コンテキストウィンドウがいっぱいになると、モデルは幻覚(ハルシネーション)を起こし始めます。各エージェントの役割を極めて焦点を絞ったものに保つことで、コンテキストの使用量を総ウィンドウの 25% 未満に抑えています。「すべてのファイルを読み取る」という単純なアプローチでは、毎回この制限を超えてしまいます。

私たちが陥った一つの落とし穴は、並列処理を実装する前に永続化(パージステンス)を考慮する必要があるという点です。予期せぬエラーのために 5 時間にわたる実行をすべて捨ててしまうようなことは避けなければなりません。各ステージは、(run_id, repo, stage) をキーとして SQLite データベースに書き込みます。どのステージでも再開や再試行が可能であり、後続の実行に引き継ぐこともでき、作業のやり直しは不要です。発見結果は発生した時点でストリーミングされ保存されるため、クラッシュが起きた場合でも、実行中のタスクのみが失われ、それ以外のデータには影響しません。

アドバイス:一時的な API エラーは、コード例外をスローする代わりに、(200 OK) 応答ストリーム内のテキストとして返されることがあります。オーケストレーターにとっては、これは完全に正常に終了したタスクと全く同じように見えます。例外タイプだけを信頼するのではなく、応答テキストを明示的に分類する必要があります。そうしないと、空の実行が成功として記録されてしまいます。

動的脅威モデリング

Recon(偵察)ステージでは、エージェントは脅威モデルを受け取るのではなく、自ら作成します。注入、メモリ破壊、プロトコル解析、タイミングサイドチャネルなど、約 10 の組み込み攻撃クラスを超えて、Recon エージェントはその場でリポジトリ固有のクラスを新たに発明し、それぞれに独自のメソドロジーを持たせることができます。これはそのコードベースに特化したカスタム分類体系を作成するものであり、Hunter(ハンター)エージェントの範囲をより厳密に限定するために使用されます。

ソースコードを読むだけでは、ストレス下での動作を理解するには不十分です。特に C 言語やその他の低レベル言語における微妙な未定義動作バグについてはなおさらです。Hunter エージェントはコードの読み取りを超えて、アクティブな実行へと移行します。断片をコンパイルし、小型版を構築して攻撃を行います。品質が飛躍的に向上した最大の要因は、バイナリをクラッシュさせるためのサンドボックス(unshare をベースに構築)を Hunter に与えたことです。

アドバイス:ハーンセス自体が Docker 内で実行される場合、そのサンドボックスには seccomp=unconfined および apparmor=unconfined を設定する必要があります。これらを指定しないと、起動時に静かに失敗してしまいます。ネスト型コンテナ化の専門家でない限り(私たちもそうでしたが)、これを 1 行で修正するだけで、頭を抱える一日を節約できます。

マイクロフォークとウィッシュリスト

コアパイプラインステージ以外に、ハンターが分析の進行を妨げずに焦点を適応させたり外部リソースを要求したりするための自律性を付与する 2 つの専門メカニズムを追加しました。

兄弟フォーク:これは、ハンターエージェントが現在のスコープ外の興味深いコードパスに遭遇した際に、軌道から逸脱しないようにするために役立ちます。この機能は、正確な構造的シードを持つ兄弟エージェントをフォークするためのツール呼び出しを使用します。フリート全体ではタスクの約 9% を占めますが、その割合はモデル依存性が非常に高く、どのモデルがハンティングを行っているかによってほぼゼロから約 5 分の 1 の範囲で変動します。

願望リスト:エージェントが持っていないツールを必要とする際、特に Proof of Concept (PoC) を確認する Validator や、特定のビルド環境、仮想マシン (VM)、あるいは本番構成ファイルなどを構築したい Hunter の場合、中央の願望リストに書き込みます。これにより、人間が依存関係を満たした時点でシステムがその正確なタスクを自動的に再実行できるよう十分な文脈が提供されます。これらの一部は部分的に自己修復が可能です:コンテナに変更を加えて再ビルドする必要がある場合、汎用的なコーディングハーンチスがログを監視することで、実行後に自律的に発生させることができます。

願望リストは追加されて以来、128 のリポジトリ全体で 25,472 回書き込まれており、エージェントが私たちに報告する主要な手段となっています。執筆中に着信した一例に「この PoC をエンドツーエンドで確認するために FreeBSD VM が必要だ」というものがあります。

フリート全体のクロスリポジトリ追跡

初期のクリーンアップ後、トレーサーエージェントは異なるソフトウェアコンポーネントがどのように接続されているかを確認します。特定のパスを探します:潜在的な攻撃者が外部から有害な入力をシステムの脆弱な部分に送信できるかどうかです。答えがイエスであれば、トレーサーエージェントは自動的に消費者リポジトリ内で新しいハンティングタスクを起動します。これを機能させるには、統一されたクロスリポジトリシンボルインデックスと正確な依存関係グラフが必要です。これにより、標準的な単一リポジトリスキャンでは見逃される可能性のある深層的で体系的な欠陥を発見することができます。

フルセットのリポジトリに対してハーンを走らせることで、スケーリングした際に初めて浮き彫りになった2 つの教訓がありました。

まず、重複排除はそれ自体が大きな問題であり、専用のエージェントが必要になるほどです。数個のリポジトリをスキャンする程度であれば、手動で重複するバグを目視確認できます。単純な文字列マッチングやファイルパスチェックではここでの問題は解決できません。2 つの複雑なロジック欠陥が実際に全く同じ根本的なバグであるかどうかを判断するのは一見簡単そうに思えますが、実際はそうではありません。そこには多大な認知的推論が必要となるため、ノイズを除去するために専用の重複排除(Dedup)エージェントを配備し、独自のヒューリスティックと作業削減手法を持たせる必要がありました。

2 つ目は、静的解析ツールを早期に組み込まないことです。Semgrep をフルスタックで実装しましたが、ハントラーたちは1 か月の運用期間中一度もそれを呼び出しませんでした。彼らはコードを読んで実行することを好みます。一方、ウィッシュリストはシステム内で最も頻繁に使用されたツールでした。エージェントが実際に何に手を伸ばすかに注目することが、あなたが彼らが必要だと考えるものよりも重要です。

信頼できる発見結果を作成する

エージェントは、自身のエクスプロイトが機能するようにソースコードを編集し、作成したバグを堂々と報告します。あるいは、「exec() は何かを実行するものであるため、重要な脆弱性である」といった全く同語反復的なことを証明するテストを書いたり、脅威モデル自体が無意味なために何も証明できないが動作はするエクスプロイトを作成したりします。もしあなたのハーンネス(検証環境)がこの傾向に積極的に対抗しないなら、あなたが構築したのは単にゴミをより速く生産するための手段に過ぎません。

ハンターは、何らかの報告を行う前に必ず脅威モデルを明示しなければなりません。攻撃者が誰であるかを正確に定義し、その脆弱性がどの境界を越えるのか、あるいはどの前提条件を破るのかを明確にする必要があります。出力スキーマの順序付けがこの要件を強制します。この要求により、「ユーザーがデータベースへの書き込み権限を持っていれば、データベースに書き込める」といった空虚な発見や、「データベースへの書き込み権限を持つユーザーはデータベースに書き込める」といった類の報告を排除できます。

⟦CODE_0⟧

すべての確認された発見には、オリジナルの untouched コードベースに対して実行されるテストとして記述された PoC が付属します。これにより、エージェントがソースファイルを編集して強制的にエクスプロイトを成立させることが防止されます。動作する PoC がない場合、その発見は偽物として扱われます。実際には、これは Hunter が三十行程度の解析ループをコンパイルし、メモリ保護を有効にして実行し、誤った読み取りストライドが期待されるメッセージ本体ではなくスタックアドレスから発生していることを実証するものです。これを自分自身で再実行することも可能です。さらに、すべての確認された発見には提案されたパッチも付属しなければなりません。実際にレビューキューに到達するのは、検証済みのバグ、動作するテスト、そして機能的な git diff であり、単なる問題の漠然としたテキスト記述ではありません。

エクスプロイト経路が生き残る前には、決定論的なコード(別のモデルではなく通常のコードで記述されたもの)が機械的に、引用されたファイルとパスが実際に存在することを確認し、パッチとテストの両方が正しく構文解析されることを確認します。この Validator は独自の発見をログに記録することはできません;その唯一の仕事は Hunter の理論を積極的に反証することです。Hunter に自分の宿題を採点する権限を与えれば、出力したすべてのものを自信を持って検証してしまうでしょう。

当システムについて偽陽性率を主張するものではありません。コードベース内のすべての実際のバグにラベル付けされたセットが存在しないため、いかなるリコール数値の主張も完全に推測に基づくものです。私たちが監視できるのは、再実行で新たなバグが継続して発見されるか(実際そうであり)、また各実行を通じてカバレッジがまだ拡大しているかどうかです。これは単なる代理指標に過ぎません。なぜなら、単一のコードベース内に実際に存在するバグの数を確実に知ることはできないからです。しかし、効果性を測定するための十分に良い方法ではあります。

ステージ 2: 脆弱性検証システム (VVS)

ハーネスから得られた発見は、トリアージプロセスの始まりに過ぎません。すべての発見物は現在、145 のリポジトリ全体で合計 13,841 の発見物を保持している単一の共有 VVS に集約されます。この量のトリアージを行うことはそれ自体が巨大なエンジニアリング課題であり、ハンティングと同様に重要です。そのトリアージエンジンは、ハーネスとは異なるモデルに基づいており、3 つの明確に区別されたジョブに分解されています。

エージェント/ステージ

主要な役割

スパーン/サブエージェント/ツールリング

重複排除 (Dedup)

脆弱性がすでにシステム内に存在するか、または内部 Jira チケットとして既に提出されているかを識別する

決定論的:単純なコードビルドがファイルに対して逆インデックスを構築し、f

原文を表示

A few weeks ago, we published our initial findings from Project Glasswing, looking at what happens when you point frontier security models at an enterprise codebase. We also explored how our defensive structures adapt to protect our infrastructure and customers from threats posed by frontier AI. Since then, the AI ecosystem has continued to shift rapidly — developers who've built tightly around a single model have already experienced what happens when that model is no longer available or gets superseded by a more capable one. These market shifts only reinforce our core thesis: no matter which underlying model is leading the pack on any given day, the future of agentic workflows will not be found in standalone models, prompts, or single-agent sessions.

Moving from a localized security "skill" to a continuous, fleet-wide scanning pipeline requires an architecture where models are treated as interchangeable components. Relying on a single model inherently limits defensive coverage, as the same system will tend to look at code paths through the exact same lens. To counter this, models should be frequently interchanged and cross-tested. By varying the models across the pipeline — such as using one model for initial discovery and an entirely different one for validation — we can ensure that vulnerabilities are cross-checked by distinct sets of logic. Furthermore, a true enterprise-scale harness must look beyond isolated repositories to trace vulnerabilities across cross-repo dependencies, ultimately filtering thousands of raw candidates down to a trusted, triaged queue of actionable fixes.

This post serves as a practical look at how to build that model-agnostic layer, focusing on how we manage state controls, eliminate false positives, and coordinate end-to-end triage at scale.

Two objections, up front

The first post made the case for why generic coding agents can't do this job. The main issue is that agents only hold one hypothesis at a time, fill their context window after covering a sliver of a real repo, and then lose information during context compaction. For more details, read that post.

Before we move forward, we would like to answer two likely questions.

"Why not use subagents instead of a harness?" Subagents are useful, and they are a good starting point. But security analysis needs hundreds of separate investigations that survive across runs, don't share a context window, and can be re-scoped and cross-referenced later. It needs persistence, deduplication, resumability, and eventually fleet-wide dependency tracing. That's an orchestration problem, and a prompt can't get you there.

"Is this blog post just an ad for frontier models?" No. Our approach centers on the harness, not the model. When it comes to vulnerability discovery, we run it with whatever frontier model is currently best at what we need. When we point different models at the same target, they each turn up a different share of the bugs. The harness is the bit that lasts. If you build your own system, design it to be model-agnostic from day one. This will allow you the freedom to use any model of choice without constraints.

It all starts with a skill

We started with a ~450-line security-audit skill that we ran on a single repository, and adjusted the prompts until we surfaced real bugs. Later, we added the orchestration that became the plumbing of the entire system. The real value lives in the prompts themselves, and our prompts continue to carry the initial skill's attacker scenarios, bug classes, and anti-pattern detections nearly unchanged.

The skill was written to run a 7-phase audit in one session:

Three parallel research agents do recon and write an architecture.md.

One Hunter agent runs per class attack, trying to break the code rather than review it.

Adversarial validators try to disprove each finding.

The survivors are written up as a human-readable vulnerability report.

They're also emitted as findings.json against a schema, and a mechanical check validates that file.

Finally, a fresh agent independently re-verifies every finding against the source.

The surviving, re-verified findings are submitted to the ingest API.

That first skill maps almost directly onto the later harness:

Skill phase

Harness stage

Recon agents write architecture.md

Recon

Hunters run per attack class

Hunt

Validators disprove findings

Validate

Surviving findings become a report

Report

findings.json is checked mechanically for schema adherence, not correctness

Mechanical validation of line numbers and functions in findings

Fresh agent re-verifies findings

Independent validation

The skill worked, but it quickly revealed its limits. Looking at the coverage metrics, a single run finds only about half the bugs you'd catch across multiple runs. In our experience the ones it did find skewed toward the simpler and less subtle. Once your process is basically "run it ten times and diff by hand," you probably need to start looking at a real harness.

While running and fine-tuning the skill, we ran into three walls:

Context exhaustion: An hour in, the context window fills up and the model will cannibalize its own memory, instantly forgetting the bugs it spent all morning tracking down. We broke this bottleneck by externalizing the state entirely, treating the LLM as a stateless compute engine.

Persistence: A crash mid-run means starting over. Losing hours of work to one AI rate-limit error or connection flakiness is an incredibly expensive way to realize you need a better architecture.

Cross-repo reasoning: A single repo session is completely blind to the relationships between applications that consume it, and the number of bugs that surface when you inspect the interface between components is probably more than one might expect.

ADVICE: A real but minimal harness consists of just Recon, Hunt, and Validate stages kept in a database, alongside a separate Validator that can't file its own findings. You should skip cross-repo tracing entirely until you have more than one repository that matters. Skip a dedicated Deduplication agent until you are actively drowning in noise. Start with a skill in your development environment, get your prompts working well, and only build the next architectural stage when not having it is the specific thing slowing you down.

Codifying the skill into a pipeline

Most AI security write-ups in this space are about a single repo or a curated benchmark; running a whole fleet this way, with cross-repo tracing, isn't something we've seen written up elsewhere. Our codebase spans a massive mix of languages — Rust, Go, C, Lua, TypeScript and Python, alongside various configuration management systems, static configs, and all sorts of additional context. So we had to come up with something new that worked for us. Going from that first slash-command run to a fleet scanner that could cover 128 distinct repos, automatically finding and interrogating relevant dependencies, took about six weeks. Codification was mostly mechanical: we lifted each phase of the skill into its own agent, put a database behind it and an orchestrator in front. The mapping was almost one-to-one.

The entire fleet runs on one unified harness with no per-language tuning and traces the dependencies between repos. While offloading syntax to a model makes the system language-agnostic, the differentiator is its ability to trace dependencies between repos. The harness itself doesn’t care if it’s looking at C pointers or a TypeScript file; it focuses on the higher-level logic of security orchestration. This allows us to scale across hundreds of different codebases, without having to write custom language parsing.

A two-stage vulnerability research workflow

Our entire vulnerability research workflow is built on a two-stage operational framework: the Vulnerability Discovery Harness (VDH) and the Vulnerability Validation System (VVS).

The VDH functions as our discovery engine, proactively scanning codebases to surface potential security issues. Once bugs enter the VVS, which allows multiple harnesses to feed into it, they go through stages of Deduplication, Judgment, and finally Fixing, as we’ll talk about later.

We use one model for VDH, but we use a completely different model for VVS, so the models are effectively double-checking each other. There is an obvious security benefit to this: by forcing Model B (VVS) to judge the output of Model A (VDH), you ensure that the finding is evaluated by an entirely different set of logical weights and training data — one that acts as an unbiased, adversarial third party whose sole job is to ruthlessly stress-test Model A's assumptions.  And operationally, we benefit from treating model providers like interchangeable commodities. Model providers can change temperature, caching, and inference effort budgets over time, even within one model version. Instead of building a system that depends on a model behaving predictably over time, our harness is built to absorb downstream volatility without breaking.

Stage 1: Vulnerability Discovery Harness (VDH)

The first post covered what each agent/stage is for, so we'll talk about the parts it didn't: the glue between stages, and the handful of details that decide whether any of it works.

Agent/stage

Primary Role

Sub-agents / Tooling

Recon

Maps out the target architecture and maps potential threat vectors

3 parallel Recon sub-agents write architecture.md

Hunt

Runs per-class attacks, compiles fragments, probes binaries

It spawns siblings (these handle between 9% and 20% of fleet-wide tasks depending on the model). It reaches out to and writes to the Wishlist tool.

Validate

Mechanically checks the finding, then adversarially disproves it

Runs in two passes: plain code handles the initial schema/path checks, then a single isolated agent tries to disprove the finding before it can be filed.

Gapfill

Generates new hunt tasks for empty coverage cells

Enqueues fresh hunt tasks for any under-tested (area × attack-class) cells that still look thin

Dedup

Identifies and consolidates overlapping findings

Combines deterministic code and agents to cluster findings by root cause, folding them together in real time

Trace

Walks dependency graph; spawns consumer-repo tasks

Walks the graph to add hunt tasks inside every identified consumer repo to make sure cross-repo bugs are caught

Feedback

Learns from pre-existing reports and optimizes future runs

Takes validation failures, shallow runs, and repeated misses, and instantly rewrites queued prompts to make future tasks sharper.

Report

Renders human-readable report

Just a script, no model required

Table 1: Vulnerability Discovery Harness (VDH)

Stages four through eight run as a continuous producer-consumer loop. As the initial hunt progresses, the Gapfill, Feedback and Trace agents generate new tasks; Dedup folds overlapping findings back together and the rest of the loop keeps consuming the queue. This ensures a vulnerability discovered late in the cycle is still validated, reported and checked against other code to make sure it doesn't contain the same bug, all within the same run.

Splitting the pipeline this way guarantees strict context controls. If you fill the context window, the model starts hallucinating. We keep each agent’s job hyper-focused, keeping context usage below 25% of the total window. A naive “read all files” approach will blow past this limit every single time.

One thing that caught us out was that persistence needs to be factored in before parallelism. You do not want to throw away a five-hour run because of an unforeseen error. Every stage writes to one SQLite database keyed by (run_id, repo, stage). Any stage can resume, retry, or get pulled into a later run without redoing work. Findings are streamed and saved as they happen, so a crash costs you the task in flight and nothing else.

ADVICE: Sometimes a transient API error comes back as text in the (200 OK) response stream instead of throwing a code exception. To the orchestrator, this looks exactly like a task that finished cleanly. You must explicitly classify the response text, not just trust the exception type, or you end up logging empty runs as successes.

Dynamic threat modeling

During the Recon stage, the agent writes the threat model instead of being handed one. Beyond about ten built-in attack classes (many forms of injection, memory corruption, protocol parsing, timing side channels, and others), the Recon agent can invent repo-specific classes on the spot, each with its own methodology. It writes a custom taxonomy tailored specifically to that codebase, which is used to more tightly scope the Hunter agents.

Reading source code isn’t enough to understand how it behaves under stress, especially for subtle undefined-behavior bugs in C and other lower-level languages. The Hunter agents move past code reading and transition into active execution. They compile fragments, build small versions, and attack them. The biggest jump in quality came from giving Hunters a sandbox (built on unshare) to crash binaries.

ADVICE: If the harness itself runs inside Docker, that sandbox needs seccomp=unconfined and apparmor=unconfined or it will silently fail to start. It’s a one-line fix that saves you a day of head-scratching if you aren't an expert in nested containerization, like us.

Micro-forks and the wishlist

Beyond the core pipeline stages, we added two specialized mechanisms that grant the Hunters significant autonomy to adapt their focus and request external resources without derailing an ongoing analysis:

Sibling Forking: This helps ensure that if a Hunter agent trips over an interesting code path that is outside the current scope, it doesn’t wander off track. It uses a tool call to fork a sibling agent with a precise structural seed. Fleet-wide, this accounts for roughly 9% of tasks, though the rate is highly model-dependent — from near-zero to about a fifth, depending on which model is hunting.

The Wishlist: When an agent needs a tool it doesn't have, often a Validator confirming a Proof of Concept (PoC) or a Hunter wanting to build something (like a specific build environment, a VM, or some prod config files), it writes to a central wishlist. It provides enough context for the system to automatically re-run that exact task once a human provides the dependency. Some of these can be partly self-healing: if the container needs to be rebuilt with some changes, this can autonomously happen after the run by having a generic coding harness monitor the logs.

The wishlist has been written to 25,472 times across 128 repos since the wishlist was added, and it's the main way the agents talk back to us. One that landed while we were writing this: "I need a FreeBSD VM to confirm this PoC end-to-end."

Fleet-wide cross-repo tracing

After the initial cleanup, a Tracer agent checks how different software components are connected. It looks for a specific path: can a potential attacker send harmful input from the outside to a vulnerable part of the system? If the answer is yes, the Tracer agent automatically spawns fresh hunt tasks inside the consumer repository. To make this work, you need a unified, cross-repo symbol index and an accurate dependency graph. This allows you to uncover deep, systemic flaws that a standard single-repo scan would miss.

Running our harness across an entire fleet of repos revealed two lessons that only surfaced when this was done at scale.

First, deduplication is its own problem, big enough to need its own agents. When you are scanning a handful of repositories, you can manually eyeball overlapping bugs. Simple string matching or file-path checks won't save you here. Determining whether two complex logic flaws are actually the exact same root bug sounds trivial, but it isn't. It requires so much cognitive reasoning that we had to deploy dedicated Dedup agents just to clean up the noise, along with their own heuristics and ways of reducing the work.

The second is to not wire in static analysis early. We plumbed Semgrep all the way through, and the Hunters invoked it zero times in a month of runs. They would rather read and run the code. The wishlist, by contrast, was the single most-used tool in the system. It's worth paying attention to what the agents actually reach for, rather than what you think they'll want.

Making findings you can trust

The agent will edit the source code so its own exploit works, then triumphantly report the bug it just created. It will write a test that proves something entirely tautological like “exec() executes things, therefore critical vulnerability”. Or it builds an exploit that runs fine but proves nothing, because the threat model behind it is nonsense. If your harness doesn't actively fight this, all you've built is a faster way to produce junk.

A Hunter has to state the threat model before it's allowed to file anything. It has to define exactly who the attacker is, and what boundary the vulnerability crosses or what assumption it breaks. The output schema ordering enforces it. This requirement eliminates the vacuous findings, the "if a user has database write access, they can write to the database" kind.

Every confirmed finding ships with a PoC written as a test that runs against the original, untouched codebase. This prevents the agent from editing the source files to force an exploit to land. If there is no working PoC, we treat the finding as fake. In practice, that's a Hunter compiling a thirty-line parsing loop, running it with memory protection enabled, and demonstrating that the incorrect read stride is originating from a stack address rather than the expected message body. You can re-run it yourself. Furthermore, every confirmed finding must also ship a proposed patch. What actually reaches our review queue is a verified bug, a working test, and a functional git diff, not just a vague text description of a problem.

Before an exploit path survives, deterministic code (written in plain code, not another model) mechanically verifies that the cited files and paths actually exist, and confirms that both the patch and the test parse correctly. This Validator cannot log findings of its own; its sole job is to aggressively disprove the Hunter's theory. If a Hunter is allowed to grade its own homework, it will confidently validate everything it outputs.

We don't claim a false-negative rate for our system. There's no labeled set of every real bug in a codebase, so any claimed recall number is entirely speculative. What we can watch is whether re-runs keep turning up new bugs (they do) and whether coverage is still growing across runs. It’s all a proxy, as you don’t know for sure how many bugs exist in a single codebase, but it’s a good-enough way of measuring effectiveness.

Stage 2: Vulnerability Validation System (VVS)

A finding coming out of the harness is just the start of the triage process, with all discoveries landing in a single, shared VVS that currently holds 13,841 findings across 145 repos in total. Triaging that volume is its own massive engineering problem, and it matters just as much as the hunting. That triage engine runs on a different model from the harness, broken down into three distinct jobs.

Agent/stage

Primary role

Spawns/ sub-agents/tooling

Dedup

Identifies if a vulnerability is already in the system, or raised as internal Jira ticket already

Deterministic: plain code builds inverted indexes over files, f

この記事をシェア

関連記事

Latent Space★42026年6月19日 14:53

[AINews] GLM は GPT より優れているか?GLM-5.2 が実用性を証明、Z.ai が 12 月までに「Open Fable」を公開予定

Latent Space のニュースでは、中国のモデル「GLM-5.2」がベンチマークで優れた結果を示し実用性があると評価されたことと、Z.ai が 12 月までにオープンソースプロジェクト「Open Fable」を発表する見込みについて報じられています。

MarkTechPost★32026年6月19日 11:44

Salesforce CodeGen チュートリアル:ユニットテストと安全性チェック付きの Python 関数の生成・検証・再ランク付け

Salesforce は Hugging Face からモデルを読み込み、自然言語から Python 関数を生成するエンドツーエンドワークフローを公開した。この手法には構文チェックや静的解析、ユニットテストによる検証が含まれる。

AWS Machine Learning Blog★42026年6月19日 08:31

CloudWatch の SageMaker メトリクスとインサイトダッシュボードを用いた生成 AI 推論の監視・デバッグ

AWS は、大規模な生成 AI 推論エンドポイントの P99 レイテンシ急上昇などのトラブルを GPU メモリ圧力や KV キャッシュ飽和などから特定できるよう、CloudWatch に SageMaker の詳細メトリクスとインサイトダッシュボードを追加した。

今日のまとめ

AI日報で今日の重要ニュースをまとめ読み

ニュース一覧に戻る元記事を読む