すべての記事に戻る

鍵を持つのは broker。AI エージェントではない。

broker の磨かれたカウンターに小さなロボットが立っている。金属格子の向こうに、Slack、GitHub、Notion、Gmail とラベルのついた鍵がフックに掛かっている。ロボットは窓越しに紙片を渡している。静かで礼儀正しいやり取り。

AI エージェントは confused deputy です。これは 38 年前に名前のついたセキュリティパターンで、答えも同じくらい古い。エージェントと、それが呼び出す必要のある SaaS API のあいだに broker を置く——信頼できる、観測可能な、決定論的な、監査可能な、改ざん不可能な、スコープが絞られた、ポリシー駆動の、AI ではない中間レイヤー——そして broker に、エージェントが持つべきでない認証情報を預ける。

1988 年、Norm Hardy が Tymshare 在籍時の実話をまとめた短い論文を発表しました。FORT という Fortran コンパイラが SYSX というシステムディレクトリにありました。利用統計を集めるため、コンパイラは (SYSX)STAT に書き込む必要があり、OS は FORT に「home files license」を与えて、SYSX 内のあらゆるファイルへの書き込みを許可していました。システムの課金ファイル (SYSX)BILL も同じ場所にありました。コンパイラを呼ぶユーザは、デバッグ出力用のファイル名を任意で渡せました。ある日、誰かが (SYSX)BILL を渡しました。コンパイラは OS にそのファイルを書き込み用に開くよう依頼し、OS は home files license を見て許可しました。課金データは上書きされました。コンパイラは設計通りに動いたのです。欠陥はアーキテクチャのほうにありました。

Hardy はこれを confused deputy 問題と名づけました。特権を持つプログラム(deputy)が自分の権限を持っている。権限の低い呼び出し元がその deputy に何かを頼む。deputy はどちらの権限を使うべきか取り違え、自分の権限を使ってしまう。修正方法は、その権限を deputy から完全に取り上げ、要求のたびに仲介する別レイヤーの後ろに置くこと。そのレイヤーが broker です。

38 年経った今、あなたの会社で動くすべての AI エージェントが confused deputy です。そして、そのほとんどが broker なしで動いています。

なぜ AI エージェントで悪化するのか

Hardy の FORT には入力経路がひとつしかありませんでした。コマンドラインです。現代の AI エージェントには数十の入力経路があります。メール本文、取得した Web ページ、アップロードされた PDF、上流 MCP サーバーからのツール出力、マルチエージェントシステム内の他エージェントからのメッセージ。コンテキストウィンドウに入るあらゆるものが指示を出せて、エージェントは設計上、それらすべてを正当なものとして扱います。

これは従来のアクセス制御が前提にしてきた約束を破ります。呼び出し元が入力を制御する、という約束です。Web アプリでは呼び出し元(認証済みセッション)と入力(HTTP リクエストボディ)は同じ出所から来ます。エージェントの場合、呼び出し元はプロンプトを形作る誰かなので、メールを送れる攻撃者や検索結果に細工できる者も呼び出し元になります。

2025 年 11 月、PromptArmor のセキュリティ研究者がこれが実環境でどう見えるかを実演しました。彼らは統合ガイド上に 1 ピクセルのフォントで悪意ある指示を仕込みました。開発者が Google の Antigravity IDE をそのガイドに向けると、エージェントはターミナルから cat を実行することで、自身の .gitignore ベースのファイル保護を迂回しました。続いて .env ファイルの中身を、Antigravity 自身のブラウザサブエージェント経由で攻撃者が制御する webhook.site URL に送り出しました。ユーザの設定は正しかった。サンドボックスも持ちこたえた。ただ、エージェントには「ユーザが指示したこと」と「入力が指示してきたこと」を区別できなかったのです。

Hardy の FORT と同じ形が、数十年たっても残っています。広い権限、信頼できない入力、両者を切り分ける手段がない。

答えは散らばっているだけ

これは新しい問題ではありません。セキュリティコミュニティは数十年にわたって答えを書いてきました。

Capability-based security(Dennis & Van Horn 1966。後の E 言語、Mark Miller の Google における Caja 研究)。原則:身分や場所に基づく ambient な権限を渡すな。プログラムが触ってよいリソースごとに、明示的かつ偽造不能な capability を渡せ。capability は「何ができるか」と「何に対してできるか」を一束にしていて、他のものと取り違えられない。

Brokered CredentialsOWASP LLM Top 10 で明文化)。API トークンを LLM のコンテキストに入れるな。信頼できる中間レイヤーがエージェントの代わりに呼び出しを行う。モデルは「何をするか」を決め、broker が「どうするか」を引き受ける。モデルに認証情報を出力させるプロンプトインジェクションは、何も役に立つものを得られない。認証情報がそこにないのです。

Phantom Token Pattern(Curity が当初マイクロサービス向けの OAuth で提唱)。エージェントは不透明なセッションハンドルだけを持ち、本物の bearer token は持たない。プロキシがハンドルを検証し、ネットワーク境界で本物の認証情報に差し替えて上流に転送する。エージェントが環境を漏らしても、攻撃者が手にするのはセッション終了で失効する文字列です。

Just-in-time credential injectionAembit のような workload identity システム)。長期トークンを発行する代わりに、呼び出しごとに短命でスコープの絞られた認証情報を発行する。

これらは文献から欠けていません。デフォルトから欠けているのです。多くのエージェントプラットフォームはいまだに、モデルに OAuth トークンをそのまま渡し、broker を間に挟まず、うまくいくことを願っています。

Zero の broker の仕組み

上のパターンを発明したわけではありません。私たちはそれらを単一の broker にまとめ、Zero のすべてのエージェントに対してデフォルトで動かしています。これらのパターンが描く信頼できる中間レイヤーを、AI エージェントプラットフォーム向けに作り直したものです。エージェントが connector に対して行うすべての呼び出しは broker を通ります。connector は外部 SaaS 一つとの接続のことです(Slack、GitHub、Notion など)。

Broker アーキテクチャ:左に Firecracker microVM 内のエージェント、中央に broker(認証情報の隔離、Connector ポリシーゲート、運用ループと監査を含む)、右に SaaS API。点線のトークン境界は、本物の認証情報が broker からエージェント側へ越境しないことを示す。 Broker はすべてのエージェントとすべての connector のあいだに位置する。本物の認証情報は点線の broker 側にしか存在しない。

3 つのレイヤーで考えます。

1. 認証情報の隔離

エージェントのサンドボックスは、本物の connector 認証情報を一度も持ちません。SaaS を Zero に接続すると、OAuth トークンや API キーは broker 側に残ります。サンドボックスが受け取るのは placeholder 文字列で、既存ツールが動き続けるのに十分なほど環境変数のシークレットらしく見えますが、上流の SaaS は受け付けません。

エージェントが登録された connector ホストへリクエストを出すと、broker がそのリクエストにマッチし、connector の認証テンプレートを解決し、ネットワーク境界で本物の認証情報を注入します。リクエストは有効な認証付きで上流に届きます。エージェントは役立つものを一度も持っていません。プロンプトインジェクションで環境変数を出力させられたエージェントが攻撃者に渡すのは、SaaS トークンではなく placeholder です。

これは Phantom Token パターンを AI エージェントに適用したものです。

2. Connector ポリシーゲート

Zero の connector は、オン/オフのスイッチ以上であるべきです。各 connector は、自身がカバーする API base と、auth の注入方法を記述します。上流サービスがスコープからエンドポイントへの安定したマッピングを公開している場合は、各 method と path をどの命名済み permission がカバーするかも記述できます。Slack の slack-api-ref はよい例です。

Slack に接続したエージェントが chat.postMessage を呼ぶと、broker はそのリクエストを chat:write にマップできます。監査ログを読むなら admin.analytics:read です。エージェントごとの permission_policies が、これらの命名済み permission の振る舞いを定義します:allow、deny、または ask。ポリシーは broker レイヤーで、認証注入の前に強制されます。モデルへのヒントではありません。エージェントが、deny された permission に該当する呼び出しを試みたら(プロンプトインジェクションで誘導されたとしても)、その呼び出しは上流ネットワークに届きません。

すべての connector が現時点でこの粒度に達しているわけではありません。一部の上流 API は、スコープからエンドポイントへの安定したマッピングを公開していません。GitHub の GraphQL API がその典型例です。REST 側はマップ可能ですが、GraphQL 側はまだです。これらの connector では、broker は引き続き認証情報の注入とネットワークパスを制御し、permission gate はプラットフォームが実際に強制できる、より粗い connector レベルやホストレベルのポリシーにフォールバックします。上流のデータが利用可能になり次第、埋めていきます。築いていないカバレッジを主張することはありません。

トークンに ambient な権限は付随しません。権限はエージェントごとに、上流がサポートする最も細かい粒度で broker が仲介します。これが capability-based の答えの半分です。

3. 運用ループと監査

Least privilege は、失敗モードが使い物になる場合だけ機能します。エージェントは育ちます。Notion から読むだけで始めた research エージェントが、6 週間後には要約を書き戻す必要があるかもしれません。他のプラットフォームでの典型的な失敗モードは、エージェントが新しい permission なしに静かに動いて壊れるか、運用者が慌ててすべてを開放しすぎ、二度と回収しないかです。

拒否された connector リクエストは構造化された 403 を返します:connector、method、path、base URL、そして broker が特定できる場合は該当する permission 名。エージェントの system prompt は、その拒否をどう診断するか、拒否のきっかけとなった permission をどうリクエストするかを示し、ユーザまたは admin 向けのワンクリック grant URL を作り出します。これにより、エスカレーションのパスは具体的に求められた permission と紐づいたままになり、「もう全部開けて終わりにしよう」にはなりません。

permission 変更リクエストはキューに入ります。owner と admin はダッシュボードから承認または拒否でき、承認されたものはエージェントのポリシーを更新し、次のリトライがそのまま通ります。多くのプラットフォームがこのループを省いています。これがないと、「最小権限」はスライドの上にしか存在せず、本番では動いていません。

同じ broker パスが監査にもデータを供給します。Run ごとのネットワークログは、サンドボックスのネットワーク活動を、HTTP、TCP、DNS、さらに非 TCP トラフィック向けの低レイヤーパケット観測まで含めて記録します。connector にマッチしたリクエストは、構造化された broker メタデータを伴います:connector、利用可能な場合は該当 permission、allow/deny の結果、認証解決メタデータ、課金フラグ。あとから「このエージェントは火曜の 15 時に何をしたのか?」と訊かれたとき、その記録から答えを再構築できます。予防は何かを必ず取りこぼします。何が起こったかを知る手段が監査ログです。

まだ解けていないもの

ここまで揃っていても、正当な chat:write を持つエージェントは、すでにアクセス権のあるチャネルに、都合の悪いメッセージを投稿させられる可能性があります。Broker は被害範囲を狭めますが、消し去りはしません。

答えのもう半分は、ハイリスクなアクションの承認、出力の検証、ツールの返り値をデフォルトで信用しないことです。これは roadmap であって、まだ製品ではありません。confused deputy をエンドツーエンドで解決したと主張する人は、何かを売ろうとしています。

これは土台であるべきで、機能ではない

Capability-based security は 1970 年代からあります。Brokered credentials は OWASP LLM Top 10 にあります。Phantom token は LLM の話題より古くからあります。これらが欠けているのは、誰も答えを知らなかったからではありません。初期のエージェントプラットフォームが「デモを通すこと」を最適化し、セキュリティを後のリリースに回したからです。多くの場合、その後のリリースは来ませんでした。

次世代のプラットフォームはもっと高い目標を掲げるべきだ。トークンはモデルのコンテキストに入れるべきではない。権限はエージェントごとに列挙すべきだ。権限のエスカレーションは人を介すべきだ。すべての行動はエンドツーエンドで監査可能であるべきだ。どれも新しくない。すべてベースラインであるべきだ。

エージェントプラットフォームを選ぶとき、「これは安全ですか?」では何も分かりません。どのベンダーも「はい」と答えます。よりよい質問は「broker を見せて、エージェントが持っていない scope を要求したときに何が起こるかを順を追って説明してください」です。


Broker は Zero のすべてのエージェントの前にデフォルトで立っています。Connector の一覧、scope のマッピング、permission ポリシー、broker のロジックは、すべて Zero のソースリポジトリに公開されています。カバーしていない connector があれば、issue を立ててください。


参考文献

基礎

引用した実例

関連記事

最新情報をキャッチ

// エージェントネイティブ開発の最新インサイトを入手。

購読するDiscordに参加
鍵を持つのは broker。AI エージェントではない。 | VM0