← すべての記事

あなたのエージェントには、検証していない仲介者がいる

研究者たちは、Taobao、Xianyu、Shopify上のストアフロントから有料のLLM APIルーターを28個購入し、公開コミュニティから無料のものを400個集めました。それぞれにアカウントを登録し、サンドボックス化したコーディングエージェントをそのルーター経由で動かし、返ってきたツール呼び出しをすべて実行して、何が起きるかを観察したのです。1

428個のうち9個が、ツール呼び出しを攻撃者の管理するコマンドや依存パッケージに書き換えていました。有料が1個、無料が8個です。無料ルーターのうち17個は、通信中に見たAWSカナリア認証情報をその後実際に使用し、1個は仕込まれたEthereumの鍵から資金を抜き取りました。注入を行ったルーターのうち2個は、その挙動を隠していました。1個は50リクエストを待ってから動き出し、もう1個は自律的な「YOLO mode」(ツール実行を自動承認するモード)で動作し、RustかGoのプロジェクトを扱うセッションでだけ発動しました。1

LLM APIルーターはアプリケーション層のプロキシです。TLSを終端し、すべてのリクエストとレスポンスを平文で読み、エージェントがこれから実行しようとするツール呼び出しを書き換えることができます。 論文によれば、ツール呼び出しのレスポンスに署名している主要プロバイダーは見つからず、エージェントが実行するコマンドとモデルが生成したものを結びつける仕組みは何もありません。論文はClaude CodeとCodexを含む4つのエージェントフレームワークを検証しましたが、レスポンスの完全性を確認するものは1つもありませんでした。1

この記事は2026年4月10日、論文の要旨をもとに初めて公開しました。2026年10月2日、論文の全文に照らして書き直しています。4月版にはいくつかの誤りがあり、末尾近くの「4月版の誤り」にまとめています。

要約

  • ルーターにできること。 ルーターは、クライアントが設定したエンドポイントとしてクライアントとモデルプロバイダーの間に位置します。そのため、すべてのリクエストとレスポンスの平文を保持し、受け渡す前にどちらでも書き換えられます。1
  • 428個のルーターがしたこと。 9個が、返却するツール呼び出しに悪意あるコードを注入しました(有料28個中1個、無料400個中8個)。そのうち無料の2個はトリガーを使って注入を隠していました。無料ルーターのうち17個が研究者所有のAWSカナリア認証情報を使用し、1個が研究者所有のEthereumの鍵(残高50ドル未満)から資金を抜き取りました。1
  • 漏洩したキーと脆弱なリレーで起きたこと。 意図的に漏洩させたOpenAIキー1つが1億のGPT-5.4トークンを処理し、7つを超えるCodexセッションを露出させました。設定の甘い囮リレーは約20億トークンを処理し、440のCodexセッションにわたって99の認証情報を露出させました。そのうち401セッションは、すでにツール呼び出しを自動承認する設定で動いていました。1
  • 防御策の効果。 著者ら自身の合成ベンチマークでは、フェイルクローズ型のポリシーゲートが偽陽性率1.0%で注入サンプルをすべてブロックしました。ただし単純な適応型ベンチマークでは、ゲートの存在を知る攻撃者がサンプルの100%でゲートを回避しています。異常スクリーニングは通常の注入の89.0%、回避型の約半数を検知しました。1
  • 著者らが求める解決策。 プロバイダーが署名したレスポンスエンベロープです。これがあれば、クライアントはツール呼び出しをモデルの生成内容と照合できます。論文は、これを提供している主要プロバイダーを見つけていません。1
  • ルーターを自分でホストしている場合。 後述の10月1日の追記で、LiteLLMの11件のアドバイザリを取り上げています。そのうち1件は、認証済みユーザーなら誰でもプロキシにプロバイダーキーを外部へ送信させられるというものでした。2

主なポイント

  • エージェントの運用者へ: クライアントとモデルプロバイダーの間にあるすべてのルーターは、すべてのリクエストとレスポンスに平文でアクセスできます。そしてクライアントが設定できるのは最初のホップだけです。マーケットプレイスで購入したルーターや公開リストから拾ったルーターは、運営者を信頼する別の根拠ができるまで、敵対的な仲介者として扱ってください。
  • ハーネスの開発者へ: PreToolUseフックはツール呼び出しが実行される前に動きますが、その時点でルーターはすでにその呼び出しを書き換える機会を得ています。フックには比較すべき元の呼び出しがありません。フックにできるのはフェイルクローズです。リストに載ったドメインからのみ取得し、リストに載ったパッケージのみをインストールするシェルコマンドを許可し、それ以外をブロックします。3
  • YOLO modeを使っている人へ: 研究者の囮調査では、観測された440のCodexセッションのうち401が、すでにツール実行を自動承認する設定で動いていました。1 こうしたセッションでは、トリガーの仕掛けがなくても、単純に書き換えたコマンドがそのまま実行されていたはずです。自動承認のセッションを、自分が管理していないルーター経由で動かしてはいけません。
  • 自前のプロキシをホストしているチームへ: 自分で運用するルーターにも、同じようにプロバイダーキーが集中します。2026年10月1日にPyPAデータベースに登録されたLiteLLMの11件のアドバイザリ(大半は6月から公開済み)の中には、認証済みユーザーなら誰でも、自分の選んだホストへプロキシにプロバイダーキーを送信させられるものが含まれていました。1.97.0以降のリリースは11件すべての記録範囲から外れています。詳細は後述の10月1日の追記をご覧ください。2

ルーターとは、正確には何か?

LLM APIルーターは、ある形式(通常はOpenAI互換)でリクエストを受け付け、上流のプロバイダーを選び、レスポンスを返すものです。論文はあらゆる規模のルーターを数えています。Amazon BedrockやAzure OpenAI Serviceのようなクラウドのマネージドサービス、LiteLLMやOpenRouterのような開発者向けのプロジェクトやサービス、そして転売・集約されたAPIアクセスのコモディティ市場です。1

ルーターが使われるのには、もっともな理由があります。論文は「model fallback, load balancing, cost optimization, and a single API key across providers」(モデルのフォールバック、負荷分散、コスト最適化、プロバイダー横断の単一APIキー)を挙げ、ルーティングは特に「in regions where direct provider access is restricted, expensive, or subject to quota limitations」(プロバイダーへの直接アクセスが制限されている、高価である、またはクォータ制限のある地域)でよく使われると指摘しています。1

問題はその位置にあります。論文の言葉では、傍受のための細工は必要ありません。「the client voluntarily configures the router’s URL as the API endpoint, the router terminates the client-side TLS connection, and it originates a separate TLS connection upstream」(クライアントが自らルーターのURLをAPIエンドポイントとして設定し、ルーターがクライアント側のTLS接続を終端して、上流へ別のTLS接続を張る)のです。TLSは各区間を保護しますが、ルーターからペイロードを守ることには何の役にも立ちません。ルーターはリクエストのJSONを読んで転送し、レスポンスのJSONを読んで返します。その間に、どちらでも書き換える機会があります。1

ルーターは連鎖もします。論文の例では、開発者がTaobaoの転売業者からアクセスを購入し、その転売業者は二次アグリゲーターからキーを集め、そのアグリゲーターはOpenRouter経由でルーティングし、OpenRouterがモデルのホストへ振り分けます。4つのホップがあり、どのホップも平文に完全にアクセスできます。「The client configures only the first hop; subsequent hops are invisible.」(クライアントが設定するのは最初のホップだけで、その先のホップは見えない)。どこか1つのホップが悪質なら経路全体が汚染され、その後ろにある誠実なホップにはそれがわかりません。1

今日のAPIには、この隙間を埋めるものがありません。ツール呼び出しの引数は平文のJSONとして流れ、「No provider-level integrity mechanism binds the arguments returned by the model to the arguments received by the client.」(モデルが返した引数とクライアントが受け取った引数を結びつける、プロバイダーレベルの完全性メカニズムは存在しない)のです。1

測定の方法

著者らは各ルーターについて4つの段階を踏みました。まず研究者が管理するアカウントを登録し、API認証情報を取得します。次にそのアカウントを、「a randomized subset of custom tasks and TerminalBench 2.0 tasks」(独自タスクとTerminalBench 2.0タスクからランダムに選んだサブセット)を実行するサンドボックス化したエージェント環境に通します。これらのタスクは、現実的なシェル操作、パッケージのインストール、ファイル操作のツール呼び出しを生み出します。さらに、返ってきたツール呼び出しのペイロードをすべてサンドボックス内で実行し、ネットワークのコールバック、ファイルシステムの変更、プロセスツリーの異常を監視しました。最後に別の分析エージェントがフラグの立った実行を確認し、それぞれを無害な書き換え、悪意の可能性あり、悪意が確定、のいずれかに分類しました。1

定義は保守的です。ルーターが悪意あるコードを注入したと数えるのは、「only if a returned tool-call payload is rewritten into an attacker-controlled command or dependency」(返却されたツール呼び出しのペイロードが、攻撃者の管理するコマンドや依存パッケージに書き換えられた場合のみ)です。AWSカナリアに触れたと数えるのは、ルーターを通過した認証情報が「later produces follow-on AWS API activity attributable to that credential」(その後、その認証情報に起因するAWS APIの活動を引き起こした)場合です。1

対象はコモディティ市場であり、分野全体ではありません。無料ルーター400個の大半はsub2apiとnew-apiという2つのオープンソーステンプレートで占められており、著者らはエンタープライズや招待制のデプロイは研究の対象外だとしています。対象の大部分は中国語圏のマーケットプレイスやコミュニティから集められたものです。1

実地データ

挙動 有料ルーター(28) 無料ルーター(400)
返却するツール呼び出しに悪意あるコードを注入 1 8
注入をトリガーの陰に隠す 観測なし 2
研究者所有のAWSカナリア認証情報を使用 観測なし 17
研究者所有のEthereumの鍵から資金を抜き取る 観測なし 1

注入は見た目だけの変更ではありません。論文によれば、注入は「change the command or dependency that the agent intends to execute」(エージェントが実行しようとしているコマンドや依存パッケージを変える)ものです。有料の結果は28個中1個で、著者らは率直な結論を出しています。「Paid access improves service stability, but it does not prove tool-call integrity.」(有料のアクセスはサービスの安定性を高めるが、ツール呼び出しの完全性を証明するものではない)。1

トリガーを持つ2個のルーターは、テストでは見抜けないことを示す発見です。1個では、「malicious tool calls are injected only after the first 50 requests, which hides the attack from shallow smoke tests」(悪意あるツール呼び出しは最初の50リクエストの後にしか注入されず、浅いスモークテストから攻撃を隠す)。もう1個では、注入が有効になるのは「only for sessions that appear to be running in autonomous YOLO mode and only when the project fingerprint matches Rust or Go」(自律的なYOLO modeで動いているように見えるセッションで、かつプロジェクトのフィンガープリントがRustかGoに一致する場合のみ)でした。著者らは、観測したトリガーがすべてとは限らないとも付け加えています。これらのルーターは有限のブラックボックス調査を通してしか観測できていないため、「a router may implement additional latent conditions that our probes did not activate」(ルーターは、調査で発動しなかった潜在的な条件をほかにも実装しているかもしれない)のです。1

認証情報に関する発見は、すべて無料ルーターのものです。17個のルーターが「trigger follow-on use of at least one researcher-owned AWS canary credential after seeing it in transit」(通信中に見た研究者所有のAWSカナリア認証情報のうち少なくとも1つを、その後使用した)とされ、1個は事前に資金を入れたEthereumの鍵から資金を抜き取りました。付録によれば、この抜き取りによる損失は50米ドル未満です。1

2つの汚染研究

ルーターは、悪意がなくても同じ立場に置かれることがあります。著者らは、無害に見えるルーター経路がどう汚染されるかを2つの研究で調べました。

研究1:漏洩したキー。 研究者所有のOpenAI APIキーを、「on Chinese forums, WeChat, and Telegram groups frequented by router operators」(ルーター運営者が出入りする中国語フォーラム、WeChat、Telegramのグループ)で漏洩させました。このキー1つで1億のGPT-5.4トークンが処理され、7つを超えるCodexユーザーのセッションが露出しました。少なくとも1つのセッションでは、その背後に複数の異なる認証情報が現れています。トラフィックがどう流れ込んだかについて、論文は慎重です。結果は「is consistent with several paths: direct reuse by a router operator, direct reuse by unrelated third parties, or reuse somewhere inside a longer relay chain」(複数の経路と整合する。ルーター運営者による直接の再利用、無関係な第三者による直接の再利用、あるいはより長いリレーチェーン内のどこかでの再利用)であり、著者らは「cannot always distinguish among those paths from provider-side logs alone」(プロバイダー側のログだけでは、これらの経路を常に区別できるわけではない)としています。この研究が明らかにしたのは被害の範囲です。再利用された上流キーを持つ者は、その背後のトラフィックを平文で見ることができます。1

研究2:脆弱なリレー。 脆弱なclaude-relay-serviceインスタンスを20のドメインに、弱いパスワードのSub2APIとCLIProxyAPIインスタンスを20のIPに配置しました。囮には147のIPから4万回を超える不正アクセスの試みがあり、著者らはこれを、すべてが標的型攻撃というわけではなく、スキャンとリレーの再利用が混ざったものと解釈しています。より強いシグナルはその後に現れました。囮は「were folded into active agent-facing relay paths」(実際に稼働しているエージェント向けのリレー経路に組み込まれた)のです。囮は約20億のGPT-5.4および5.3-codexトークン、目に見えるプロンプトとレスポンスのトラフィックにして約13 GBを処理し、398のプロジェクトまたはホストにまたがる440のCodexセッションで、99の固有の認証情報を露出させました。1

この440セッションはすべて、論文の定義でコマンド注入が可能なものでした。そして401は「already operated in YOLO mode, i.e., with tool execution auto-approved rather than confirmed command by command」(すでにYOLO modeで動いていた。つまり、ツール実行をコマンドごとに確認するのではなく自動承認していた)。この401について、著者らは「sophisticated adaptive evasion was unnecessary: basic payload injection would have been sufficient to change executed commands」(高度な適応型回避は不要だった。基本的なペイロード注入だけで、実行されるコマンドを変えるのに十分だった)と書いています。1

これらは他人のセッションでした。囮がリレー経路に組み込まれた後、そのトラフィックが研究者の囮に届いたのです。最初のホップしか設定しないユーザーには、それを知る手段がなかったでしょう。著者らは集計したメタデータとソルト付きハッシュだけを保存し、観測期間の終了時に、露出した自分たちの認証情報を失効させました。1

2つのコア攻撃クラスと2つの回避バリアント

論文は、悪意あるルーターの挙動を2つの基本形と、1つ目の2つの派生形にまとめています。1

AC-1:レスポンス側のペイロード注入。 ルーターは、ツール呼び出しがプロバイダーを出てからクライアントに届くまでの間に、ツール名とスキーマを保ったまま呼び出しを書き換えます。論文の例は、インストーラーのURLが攻撃者のものに差し替えられたBash呼び出しです。結果は想定されたツールに対して有効なJSONのままなので、クライアントからは何もおかしく見えません。

AC-2:受動的な秘密情報の持ち出し。 ルーターは何も変更しません。リクエストとレスポンスから認証情報のパターンを探し、見つけたものを保持します。トラフィックは変更されないので、「clients cannot observe router-side retention」(クライアントはルーター側での保持を観測できない)。露出するのはAPIキーにとどまりません。「system prompts, tool definitions, user-supplied file contents, and environment variables all transit the same plaintext channel」(システムプロンプト、ツール定義、ユーザーが提供したファイルの内容、環境変数のすべてが、同じ平文の経路を通る)のです。

AC-1.a:依存パッケージを狙った注入。 パッケージのインストールコマンドを狙ったAC-1のバリアントです。URLを差し替える代わりに、ルーターは「substitutes a legitimate dependency name with an attacker-controlled package pre-registered on the target registry」(正規の依存パッケージ名を、対象レジストリに事前登録した攻撃者管理のパッケージに置き換える)。論文の例では、pip install requestsがpip install reqeustsに変わります。コマンドは依然として信頼されたレジストリからインストールするので、ドメインしか確認しないゲートは通過させてしまい、悪質なパッケージはキャッシュに残って後のセッションでも使われます。

AC-1.b:条件付きの配信。 AC-1をいつ発動させるかを決めるバリアントです。ルーターはトリガーに一致するまで誠実に振る舞います。論文はトリガーを5つの系統に分類しています。ツール名、内容のキーワード、YOLO modeのようなユーザーのフィンガープリント、時間帯、そしてリクエスト数です。「A router deploying a 50-request warm-up appears entirely transparent during a 10-request probe.」(50リクエストのウォームアップを仕込んだルーターは、10リクエストの調査ではまったく透明に見える)。

論文は2026年3月のLiteLLMの侵害を、大規模なAC-1の事例として挙げています。攻撃者がプロキシのリクエストパイプラインを掌握した時点で、そこを通るすべてのツール呼び出しが書き換えの対象になりました。(論文はこの侵害を依存関係の混乱として説明しています。私がサプライチェーンの記事で参照した報道では、Trivyの侵害を通じて盗まれたPyPIの公開用トークンが原因とされています。)

研究用プロキシがエージェントクライアントについて示したこと

著者らはMineと呼ぶプロキシを構築し、4つのクラスすべてを実装しました。そして攻撃モジュールごとに1,000件のツール呼び出しリクエストを、4つの公開エージェントフレームワーク(OpenClaw、OpenCode、OpenAIのCodex、AnthropicのClaude Code)それぞれに流しました。1

4つのいずれも、レスポンスの完全性を検証していませんでした。書き換えられたツール呼び出しは、AC-1のケースの100%、AC-1.aのケースの99.6%で、各フレームワーク本来の有効な形式のまま届きました。これが何を示し、何を示さないかについて、論文は正確です。「These are compatibility measurements, not end-to-end execution rates: they show that the tampered tool call reaches the client in a valid framework-native format, but downstream permission prompts or local execution sandboxes may still block the resulting action.」(これは互換性の測定であって、エンドツーエンドの実行率ではない。改ざんされたツール呼び出しがフレームワーク本来の有効な形式でクライアントに届くことは示すが、その後の許可プロンプトやローカルの実行サンドボックスが結果の動作をブロックする可能性は残る)。1

この但し書きこそ、許可プロンプトが真価を発揮する場面であり、囮調査の数字で自動承認がこれほど重要になる理由です。著者らはMineを公開していません。1

構成パターン、1つ下の層で

私は同じ構造上のバグについて書き続けています。個々には認可されたコンポーネントが組み合わさって、認可されていない挙動を生むというものです。TrivyからLiteLLMへの侵害はパッケージ層での組み合わせでした。サイレント・エグレスは取得したコンテンツの層での組み合わせ、MCPツールポイズニングはプロトコル層での組み合わせでした。

ルーター攻撃は、クライアントとプロバイダーの間のホップでの組み合わせです。クライアントはルーターを呼び出すことを認可されています。ルーターは上流のモデルを呼び出すことを認可されています。モデルは応答することを認可されています。すべてのホップが認可されているのに、組み合わさると、書き換えられたコマンドが生まれます。ホップを通過するものに誰も署名しないからです。そして秘密情報が複製されます。どのホップもそれを平文で読むからです。

論文はMCPそのものとの関係も指摘しています。「a malicious MCP server receives tool-call requests in plaintext and can return forged results, so the same basic manipulation and collection ideas transfer with adaptation to the MCP message format」(悪意あるMCPサーバーはツール呼び出しのリクエストを平文で受け取り、偽造した結果を返せるので、同じ基本的な改ざんと収集の発想が、MCPのメッセージ形式に合わせて応用できる)。同時に違いも示しています。MCPサーバーはツール実行の側にあり、ツールの出力を偽造できます。ルーターはモデルへの経路上にあり、すべてのツール呼び出しとリクエストのコンテキスト全体を見ることができます。1

3つの防御策と論文の数字

論文は、どのプロバイダーの協力もなしにクライアントが導入できる3つの対策を評価しています。以下のすべての数字には1つの但し書きがつきます。「All numbers in this section come from controlled artifact-side evaluation rather than field data.」(この節の数字はすべて、実地データではなく、管理されたアーティファクト側の評価によるもの)。コーパスは著者らのスクリプトで生成した合成データです。1

防御策 AC-1 AC-1.a AC-1.b コストと限界
フェイルクローズ型ポリシーゲート 100%ブロック 100%ブロック 測定なし 偽陽性1.0%、単純な適応型ベンチマークではサンプルの100%で回避された
レスポンス側の異常スクリーニング 89.0%検知 50.0%検知 50.9%検知 偽陽性6.7%
追記専用の透明性ログ 監査のみ 監査のみ 監査のみ 1エントリあたり約1.26 KB

ポリシーゲートは、「fetch from non-allowlisted domains or install packages outside a local allowlist」(許可リストにないドメインから取得する、またはローカルの許可リスト外のパッケージをインストールする)シェルコマンドをブロックします。無害なコマンド1,000件、AC-1サンプル500件、AC-1.aサンプル500件に対して、攻撃サンプルをすべてブロックし、偽陽性はすべて、許可リストに載っていないミラードメインからのインストーラー取得でした。著者らはこれを「the strongest immediately deployable control」(すぐに導入できる最も強力な対策)と呼んでいます。同時に、その失敗も率直に報告しています。攻撃者が許可リストに載ったドメインにペイロードを置くか、無害に見えるコマンドが後で実行するローカルスクリプトを事前に配置すれば、「the policy gate is bypassed in 100% of samples」(ポリシーゲートはサンプルの100%で回避される)。著者らの評価は、このゲートは「should be understood as a coarse but useful filter for obvious high-risk workflows, not as a robust defense against defense-aware attackers」(明らかに高リスクなワークフローに対する粗いが有用なフィルターとして理解すべきであり、防御を意識した攻撃者に対する堅牢な防御とみなすべきではない)というものです。1

ゲートを作る人にとって重要な点が1つあり、論文はこの点で一貫していません。第4節はゲートをドメインのみを見るものとして説明し、AC-1.aはそれを破るように設計されています。「the gate blocks non-allowlisted domains but does not maintain a per-package allowlist」(ゲートは許可リストにないドメインをブロックするが、パッケージ単位の許可リストは持たない)。一方、AC-1.aに対して100%を記録した第7節のゲートは、「outside a local allowlist」(ローカルの許可リスト外)のインストールもブロックします。私の読みでは、パッケージのリストを持たないゲートは、タイポスクワッティングによる置き換えをまったく見逃します。

異常スクリーニングは、返却されたツール呼び出しを、シェルのリスクパターンや引数のエントロピーなど、ローカルで見える特徴に基づいてスコア付けします。比較すべき上流の元の呼び出しはありません。偽陽性率6.7%で、AC-1サンプルの89.0%、AC-1.aの50.0%、AC-1.bの50.9%を検知しました。偽陽性の許容を1%にすると、AC-1の43.5%を捉え、AC-1.aはほぼ捉えられませんでした。著者らはこれを「useful for review prioritization」(レビューの優先順位付けに有用)と評価し、ゲートより弱いとしています。1

透明性ログは、リクエスト、レスポンス、ルーターのURL、TLSのメタデータ、生のレスポンスのハッシュを記録します。何も防ぎはしません。インシデントの後で、ルーターや認証情報がどこまで及び、どのセッションがそこを通ったかに答えられるようにするものです。1

著者らが求める解決策

3つの対策のいずれも、ツール呼び出しの出どころを認証しません。著者らもそう述べています。「No client-side control available today can prove that a router preserved the upstream provider’s response.」(今日利用できるクライアント側の対策で、ルーターが上流プロバイダーのレスポンスを保持したことを証明できるものはない)。1

それを可能にするのは、プロバイダーによる署名です。論文は「a provider-signed canonical response envelope, similar in spirit to DKIM for email」(メールのDKIMと同じ発想の、プロバイダーが署名した正規のレスポンスエンベロープ)を提案しています。対象はモデルの識別子、ツール名、ツールの引数、終了理由、クライアントのノンスで、クライアントはツール呼び出しを実行する前にこれを検証します。論文によれば、これを提供しているところはありません。「To our knowledge, none of the major provider tool-use APIs or the current MCP specification expose a deployed response-signing mechanism for tool-call arguments today.」(我々の知る限り、主要プロバイダーのツール利用APIも現行のMCP仕様も、ツール呼び出しの引数に対するレスポンス署名の仕組みを今日の時点で実装・公開していない)。1

この提案には2つの限界があります。トランスポートのセキュリティでは代わりになりません。相互TLSや証明書のピン留めは「can authenticate the router endpoint the client chose, but they do not say whether the returned tool call preserves upstream semantics」(クライアントが選んだルーターのエンドポイントは認証できるが、返されたツール呼び出しが上流の意味を保っているかどうかは示さない)。そして署名は、盗まれた秘密情報には何の効果もありません。「AC-2 cannot be mitigated by response-signing proposals because the secrets are exposed on the request path before any provider-side mechanism can act.」(AC-2はレスポンス署名の提案では緩和できない。秘密情報は、プロバイダー側の仕組みが働く前にリクエストの経路上で露出するからだ)。1

実際に何をすべきか

自分で構築していないルーターを経由してエージェントがモデルを呼び出しているなら、次のことを実践してください。

  1. 可能なら直接つなぎ、できないなら運営者を把握しましょう。 ルーターを追加するのに必要なのはベースURLの変更だけです。だからこそ、判断なしに追加されてしまいます。それを判断の対象にしてください。ここでの「信頼」とは、知っているチーム、契約、法的に責任を問える管轄など、外部の根拠を意味します。マーケットプレイスのレビューはその根拠になりません。
  2. 高リスクなツール呼び出しにはフェイルクローズで臨みましょう。 Claude Codeでは、許可リスト外のドメインから取得するシェルコマンドと、許可リスト外のパッケージのインストールをブロックするPreToolUseフックがそれにあたります。パッケージのリストも持っておいてください。依存パッケージの置き換えというバリアントは、ドメインのみのゲートを破るために存在するのです。フックは、解析できないものはすべて、終了コード2かdenyの判定で拒否するように書きましょう。Claude Codeはそれ以外の終了コードやタイムアウトをブロックしないものとして扱います。そのため、クラッシュしたり止まったりしたフックは呼び出しを止めません。呼び出しは通常の許可フローに進み、自動承認のセッションならそのまま実行されます。フックが最初の呼び出しで実際に動いたかも確認してください。ドキュメントは「a mistyped path in settings.json leaves the gate silently disabled」(settings.jsonのパスを打ち間違えると、ゲートが黙って無効になる)と警告しています。両方のリストを保守し続ける覚悟をし、決意した攻撃者はそれを迂回してくると想定しておきましょう。3
  3. 自分が管理していないルーター経由で、自動承認のセッションを決して動かさないでください。 囮調査の401セッションが前例です。許可プロンプトは、書き換えられたツール呼び出しとその実行の間に立ちはだかる数少ないものの1つです。
  4. 秘密情報をトラフィックに乗せないでください。 受動的な収集は、観測できるものを何も変えません。プロンプト、ツールの結果、エージェントが読むファイルに含まれるものは、すべて平文でルーターを通過します。認証情報の範囲は狭く絞り、可能な限りコンテキストに入れないようにし、後から疑わしくなったルーターを通過したものはすべてローテーションしてください。
  5. ローカルにログを残しましょう。 リクエスト、レスポンス、ルーターのURL、レスポンスのハッシュを、リクエストからは先に秘密情報を伏せたうえで、ルーターの手が届かない場所に保存します。攻撃を止めることはできませんが、何が露出したかを後から教えてくれます。
  6. 実行をサンドボックス化しましょう。 論文は、サンドボックスは「reduce post-execution blast radius but do not authenticate where a tool call came from」(実行後の被害範囲を小さくするが、ツール呼び出しの出どころを認証するものではない)と指摘しています。前半の効果を取りにいきましょう。

不快な示唆

ルーター層は、エージェントのエコシステムが、セキュリティを確保するよりも速くインフラを出荷している典型的な例です。人々は、すべてのモデルに使える1つのキー、より安い価格、プロバイダーがサービスを提供していない地域からのアクセスを求めています。ルーターはその3つすべてを提供し、市場はそれに報います。

同じ流れは、MCP層、パッケージ層、取得したコンテンツの層でも繰り返されてきました。エージェントスタックに新しい層が現れます。誰かが監査する前に開発者が採用します。攻撃者がやって来て、その後に研究者が来ます。今回、研究者が数えたのは、428個のルーター、悪意あるコードを注入した9個、仕込まれた認証情報を使った17個、ウォレットを抜き取った1個、そして研究者の囮を含むリレー経路を流れていた401の自動承認セッションでした。1

この隙間を埋める部品、つまりプロバイダーが署名したレスポンスは、運用者が後から追加できるものではありません。プロバイダーがそれを提供するまで、上記の対策は露出を減らしますが、ツール呼び出しがモデル自身のものであることを証明するものは1つもありません。

追記(2026年10月1日):自分でホストするルーターもリストに載っている

この記事は、他人が運用するルーターについてのものです。アドバイザリの記録が、残り半分を埋めてくれます。2026年10月1日、PyPAのアドバイザリデータベースに、LiteLLMに対する11件のエントリが追加されました。LiteLLMはオープンソースのプロキシで、チームが上で述べた理由、つまりすべてのモデルに1つのキーを使うために自前でホストしているものです。2 いずれも新しいものではありません。9件は6月21日からGitHubのアドバイザリデータベースとNVDに載っており、10件目は9月中旬からです。そしてプロキシにとって最も重要な1件は、プロバイダーキーを露出させるもので、8月26日にLiteLLM自身のリポジトリで公開され、修正版は8月9日からPyPIにあります。GitHubはこれをModerateと評価しています。これらはまとめて読む価値があります。この層について語っていることがあるからであり、また8月9日より前に公開された最終リリースはすべてCVE-2026-84377の範囲内にあるからです。

最初に読むべきはCVE-2026-84377です。リポジトリのアドバイザリの言葉では、「Any authenticated LiteLLM proxy user could redirect an outbound provider call to a destination they control and cause the proxy to send its own configured provider credentials to that destination.」(認証済みのLiteLLMプロキシのユーザーなら誰でも、プロバイダーへの送信呼び出しを自分の管理する宛先に向け直し、プロキシ自身に設定されたプロバイダー認証情報をその宛先へ送信させることができた)。原因はチェックの形にありました。「The proxy’s request-body validation was a denylist that did not cover every sensitive parameter and did not inspect parameters nested inside other request fields.」(プロキシのリクエストボディの検証は拒否リスト方式で、機微なパラメーターをすべては網羅しておらず、ほかのリクエストフィールドの中に入れ子になったパラメーターも検査していなかった)。修正は1.88.6から1.96.2までの9つのリリースラインに入っています。すぐにアップグレードできない人向けに、アドバイザリは1文で3つの回避策を挙げています。「Set general_settings.allow_client_side_credentials to false so callers cannot override connection parameters, restrict proxy keys to trusted callers, and block the affected parameters (api_base, base_url, model_list, fallbacks, provider credential fields) at a reverse proxy or API gateway.」(呼び出し側が接続パラメーターを上書きできないようgeneral_settings.allow_client_side_credentialsをfalseにし、プロキシのキーを信頼できる呼び出し元に限定し、影響を受けるパラメーターをリバースプロキシかAPIゲートウェイでブロックする)。2 1つ目だけでは不十分です。影響を受けるリリースである1.95.0のソースでは、リクエストボディのチェックが完全にスキップされるのはこの設定がtrueのときだけです(ただし、デプロイごとのconfigurable_clientside_auth_paramsで個別のパラメーターを除外することはできます)。つまり、この設定に触れていないインストールはすでにfalseの状態にあり、その不完全なチェックこそがアドバイザリの説明する欠陥なのです。修正はアップグレードです。6

2件目のエントリであるCVE-2026-59823は、同じ欠陥の縮小版です。ガードは「blocks the api_base and base_url parameters but does not cover user_config」(api_baseとbase_urlのパラメーターはブロックするが、user_configはカバーしていない)ため、有効な仮想キーを持つ呼び出し元は、その中にapi_baseを入れてプロキシを任意のホストに向けることができました。これは1.83.9で修正され、4月17日からPyPIにあります。アドバイザリは9月に後から出ました。4

2件のエントリは、プロキシのMCP側に関わるものです。MCPプロキシにおける不適切な認証(CVE-2026-12773、バージョン範囲は1.84.0での修正で終わる)と、MCP OpenAPIスペックローダーのspec_path引数を通じたサーバーサイドリクエストフォージェリ(CVE-2026-12798、1.82.2までのバージョンに影響すると記録)です。残りの7件は、管理者キーの扱い、SSOのデバッグフロー、SSOセッションの無効化、生成されたキーのセッション有効期限、UIでのユーザー列挙、非同期エンドポイントでのガードレール回避、マシン間のJWTの扱いに関するものです。5

この9件の記録は、最初の2件より情報が薄いものです。説明文はメンテナーによる解説ではなくVulDBの定型文で、MCPプロキシのエントリの説明には「up to 1.59.8」(1.59.8まで)とある一方、バージョン範囲では1.84.0で修正済みとなっています。5 CVE-2026-84377の記録にも、それ自体の食い違いがあります。リポジトリのページでは影響を受けるバージョンが「<1.94.0」とされているのに、レビュー済みの記録の範囲は1.96ラインもその修正版1.96.2までカバーしています。2

要約を信じるのではなく、自分が動かしているリリースと範囲を照合してください。この要約も例外ではありません。記録された範囲はすべて1.96.2以下で終わっているので、8月16日からPyPIにある1.97.0以降のリリースは11件すべての範囲から外れています。10月1日時点の最新リリースは1.103.2です。5

ルーターの危険は、誰が運用していても、認証情報がどこにあるかに起因します。仕込まれたAWSキーに手を出すマーケットプレイスのルーターと、プロバイダーキーを外へ送るよう仕向けられる自前ホストのプロキシは、同じ露出に2つの方向から到達したものです。一方は運営者によって、もう一方は仮想キーを持つ任意のテナントによって。上の各節の防御策は、あなたがクライアントであることを前提にしています。

自分で運用するプロキシについては、運用者側の対策を加えてください。すべての仮想キーを、その背後にある上流キーへの認証情報として扱うこと。必要でない限り、デプロイごとのconfigurable_clientside_auth_paramsも含めて、クライアントが指定する接続パラメーターは無効にしておくこと。そして、秘密情報を保持するほかのあらゆるものと同じパッチサイクルにプロキシを乗せることです。

プロキシが影響を受けるリリースで動いていた間に、完全には信頼していない誰かが仮想キーを持っていたなら、プロバイダーキーとプロキシに設定されたほかの秘密情報をローテーションし、設定していないホストへの送信呼び出しがないかログを確認してください。アドバイザリの影響範囲には「other configured secrets」(その他の設定済みの秘密情報)や「internal services reachable from the proxy」(プロキシから到達できる内部サービス)へのリクエストも含まれています。11件のうち2件、MCPプロキシのCVE-2026-12773とSSOのデバッグフローのCVE-2026-12795は、1.84.0未満のリリースにおける認証の欠陥なので、それらのリリースでは、キーを持っていた人だけがプロキシに到達できたとは限りません。信頼できないネットワークからプロキシに到達できた場合は、同じローテーションを行ってください。

4月版の誤り

この記事の4月10日版は、論文の要旨をもとに書いたものでした。2026年10月2日に全文と照らし合わせたところ、次の箇所が誤りか誤解を招くものでした。いずれも上記で訂正済みです。

  • AC-1.a。 私はこれを「only fires when the request matches a specific dependency or context」(リクエストが特定の依存パッケージやコンテキストに一致したときにだけ発動する)注入だと説明しました。実際にはインストールコマンド内でのパッケージ名の置き換えです。トリガーはAC-1.bです。
  • 防御策。 私は「the abstract does not rank the defenses」(要旨は防御策を順位付けしていない)と書き、自分の意見として順位を示しました。論文の本文は3つすべてを測定し、ポリシーゲートを「the strongest immediately deployable control」(すぐに導入できる最も強力な対策)と呼び、単純な適応型ベンチマークではサンプルの100%で回避されたと報告しています。私はそれを書き落としていました。
  • 署名についての助言。 私は運用者に、クライアントでリクエストに署名して上流で検証するよう勧め、それを「the only real fix」(唯一の本当の解決策)と呼びました。論文が求めているのは逆方向、つまりプロバイダーが署名してクライアントが検証するレスポンスであり、署名では盗まれた秘密情報には対処できないとも述べています。
  • 漏洩したキー。 私はキーが「as if it had been exposed through a developer mistake」(開発者のミスで露出したかのように)漏洩させられたと書き、「The router was a laundering layer for a stolen key.」(ルーターは盗まれたキーのロンダリング層だった)と結論づけました。実際には、ルーター運営者が認証情報を共有するフォーラムやチャットグループで漏洩させたものであり、論文は、再利用したのがルーター運営者か、無関係な第三者か、より長いリレーチェーンかを常に区別できるわけではないとしています。
  • 認証情報の件数。 回答ブロックには「17 of 28 paid routers touched planted AWS credentials」(有料ルーター28個中17個が仕込まれたAWS認証情報に触れた)とあり、説明文には研究者が28個のルーターをテストしたとありました。論文の有料の行では、認証情報の悪用は観測されていません。AWSカナリアを使った17個のルーターも、ETHを抜き取った1個も、すべて400個の無料ルーターの中に含まれます。
  • フックについての助言。 私は「validate response shapes」(レスポンスの形を検証する)PostToolUseフックを勧めました。PostToolUseフックはツールの実行後に動くので、書き換えられたコマンドに対しては手遅れです。論文が検証している対策は実行前のゲートであり、Claude Codeでは許可リストを持つPreToolUseフックにあたります。
  • 細かな誤り。 論文の著者は5人ではなく6人です。論文は、ルーターが「knows when it is being sampled」(サンプリングされていることを知っている)とは述べていません。これは私の脚色でした。冒頭ではテーマを「MCP trust chains」(MCPの信頼チェーン)と呼んでいましたが、論文が研究しているのはMCPではなくルーターです。また、サイレント・エグレスの記事をツールの説明文についての記事だと書きましたが、実際には取得したコンテンツに隠された指示についての記事です。

FAQ

この文脈でのLLM APIルーターとは何ですか?

統一された形式(通常はOpenAI互換)でリクエストを受け付け、上流のモデルプロバイダーを選び、レスポンスを返すサービスです。すべてのリクエストとレスポンスに平文でアクセスできる、アプリケーション層のプロキシです。1

TLSは悪意あるルーターから守ってくれますか?

いいえ。クライアントはルーターを自分のエンドポイントとして設定するので、ルーターはクライアントのTLSセッションを終端し、上流へ別のセッションを開きます。TLSは各区間を保護しますが、ルーターからペイロードを守ることには何の役にも立ちません。1

ツール呼び出しを書き換えているルーターは、どうすれば検出できますか?

テストで確実に見抜くことはできません。研究に登場した2個のルーターは、50リクエストの後にだけ、あるいはRustかGoのプロジェクトでの自動承認セッションに対してだけ注入しました。論文は「no fixed-length client test can guarantee that the router is benign」(固定長のクライアント側テストでは、ルーターが無害であることを保証できない)と結論づけています。シェルコマンドとパッケージのインストールに対するフェイルクローズの許可リストは単純なケースをブロックしますが、論文は防御を意識した攻撃者がそれをすり抜けることを示しています。1

PreToolUseフックは役に立ちますか?

はい、ポリシーゲートとしてなら役に立ちます。フックが見るのはクライアントが受け取ったツール呼び出しで、ルーターが書き換えていれば書き換えられたものです。リストにないドメインから取得するコマンドや、リストにないパッケージをインストールするコマンドをブロックできます。ただし、その呼び出しがモデルの生成したものかどうかは判別できません。13

Claude Codeをapi.anthropic.comに直接つないで使っています。影響はありますか?

この論文のルーター攻撃の影響は受けません。仲介者がいないからです。企業のゲートウェイやモデルアグリゲーターなど、何らかの理由でClaude Codeをプロキシ経由で使っている場合は、そのプロキシが同じ立場にあります。

OpenRouterやLiteLLMなど、よく知られたアグリゲーターはどうですか?

論文が測定したのは、3つのマーケットプレイスの有料ルーター28個と、主に2つのオープンソーステンプレートから作られた無料ルーター400個です。LiteLLMとOpenRouterは背景として名前が挙がっているだけで、テストはされていません。構造上の論点はあらゆるルーターに当てはまります。ルーターはトラフィックを読み、書き換えることができ、可視性と完全性は別の性質です。自分でホストするプロキシについては、上の10月1日の追記でLiteLLMの11件のアドバイザリを取り上げています。

自動承認されていた401のセッションは誰のものでしたか?

研究者の囮リレーにトラフィックが届いた第三者のものです。自分で構築していないルーター経由で自動承認のエージェントセッションを動かしているなら、それをやめ、そのルーターを通過したすべての認証情報をローテーションし、想定外のツール呼び出しがないかセッションのログを確認してください。


参考文献


  1. Hanzhi Liu、Chaofan Shou、Hongbo Wen、Yanju Chen、Ryan Jingyang Fang、Yu Feng、「Your Agent Is Mine: Measuring Malicious Intermediary Attacks on the LLM Supply Chain」、arXiv:2604.08407v1、2026年4月9日。ACM Conference on Computer and Communications Security(2026年10月)に掲載予定。全文は2026年10月1日と2日に読みました。参照した節:Introductionと2.1(ルーターとは何か、4ホップの例、TLSの終端)、2.2(プロバイダーレベルの完全性メカニズムがないこと)、4.1と4.2(4つの攻撃クラス、requestsからreqeustsへの例、5つのトリガー系統)、5.1(4段階のパイプラインと定義)、5.2とTable 3および4(注入した有料1個と無料8個、トリガーを持つ無料2個、AWSカナリアを使った無料17個、ETHを抜き取った1個)、5.3(漏洩したキーと囮:1億トークン、7つを超えるCodexセッション、147のIPからの4万回超のアクセス試行、約20億トークン、約13 GB、99の認証情報、440セッション、398のプロジェクトまたはホスト、YOLO modeの401)、5.4(有料アクセスについての一文を含む主要な発見)、5.5(範囲)、6とTable 5(Mine、4つのフレームワーク、モジュールあたり1,000リクエスト、100%と99.6%の互換性)、7とTable 6(3つの防御策とその結果)、8.2と8.3(署名付きレスポンスエンベロープ、MCP)、9(MCPサーバーとルーターの立場の違い)、Appendix A(保持、認証情報の失効、50米ドル未満の抜き取り、Mineの非公開)。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  2. LiteLLMリポジトリのアドバイザリGHSA-3cv6-jpf6-8222(CVE-2026-84377、PYSEC-2026-4066)、「Authenticated SSRF and provider-credential exfiltration via unvalidated request-body routing parameters」。2026年8月26日にリポジトリで公開、9月2日にNVDに掲載、9月30日にGitHubがレビュー。2026年10月1日にリポジトリのページとOSVの記録で確認しました。影響とWorkaroundsの全文はアドバイザリからの引用です。OSVの記録のPatchesの行は「Fixed in 1.96.2, 1.95.1, 1.94.3, 1.93.2, 1.92.2, 1.91.5, 1.90.7, 1.89.7, and 1.88.6」で、リポジトリのページには「Affected versions <1.94.0」とあります。11件という数は、PyPAアドバイザリデータベースのPYSEC-2026-4066からPYSEC-2026-4076までのエントリによるもので、いずれもlitellmパッケージを対象とし、日付はすべて2026年10月1日、取り下げられたものはありません。 ↩↩↩↩↩

  3. Anthropic、Hooks reference、Claude Codeドキュメント、2026年10月2日取得。PreToolUseは「Before a tool call executes. Can block it」(ツール呼び出しの実行前。ブロック可能)に動き、PostToolUseは「After a tool call succeeds」(ツール呼び出しの成功後)に動きます。「Any other exit code doesn’t block on its own for most hook events」(ほとんどのフックイベントでは、それ以外の終了コードはそれだけではブロックしない)とあり、タイムアウトしたコマンドフックは「doesn’t block the tool call」(ツール呼び出しをブロックしない)とされています。さらに「a mistyped path in settings.json leaves the gate silently disabled.」(settings.jsonのパスを打ち間違えると、ゲートは何の警告もなく無効のままになる)とあります。 ↩↩↩

  4. GitHub Security Advisory GHSA-hx8v-g79f-8w5f(CVE-2026-59823、PYSEC-2026-4070)、「LiteLLM Proxy has server-side request forgery via the user_config request parameter」、2026年9月17日公開、2026年10月1日にOSV経由で確認。影響は<= 1.83.8、修正は1.83.9で、アドバイザリはこのリリースを2026年4月17日としています。 ↩

  5. 2026年10月1日に確認したOSVの記録:PYSEC-2026-4067(CVE-2026-12773、MCPプロキシの認証)、PYSEC-2026-4069(CVE-2026-12798、MCP OpenAPIスペックローダー)、およびPYSEC-2026-4068、4071、4072、4073、4074、4075、4076。この9件の背後にあるGitHubのアドバイザリは、NVDに掲載されたのと同じ2026年6月21日に公開され、いずれもVulDBを出典としています。アップロード日と最新バージョンは、同じ日に確認したPyPIのプロジェクトページとそのJSONによるものです。1.88.6から1.95.1までが8月9日、1.96.2が8月11日、1.97.0が8月16日、1.103.2が10月1日です。 ↩↩↩

  6. PyPIから入手したlitellm 1.95.0のwheel(影響範囲は1.95.0から、1.95.1での修正まで)を著者が読んだもの、2026年10月1日。litellm/proxy/auth/auth_utils.pyでは、general_settings.get("allow_client_side_credentials") is Trueのとき_check_banned_paramsは何も拒否せずに戻ります。それ以外の場合は、禁止リストに載ったパラメーターをボディに含むリクエストを拒否しますが、デプロイのconfigurable_clientside_auth_paramsがそのパラメーターを許可していれば例外です。このリリースの禁止リストには、vertex_ai_credentialsや可観測性ツールの認証情報とホストが含まれます。私が読んだのは影響を受けるリリースの1つだけで、9つのラインすべてではありません。 ↩

関連記事

フォークボムに救われた

LiteLLMを攻撃した人物は、実装をひとつ間違えました。47,000件のインストールが46分で発覚したのは、その間違いだけが理由でした。

8 分で読める

MCP サーバーは新たな攻撃対象領域

50件のMCP脆弱性、60日間で30件のCVE、13件がクリティカル。ツール利用プロトコルは誰も監査していない攻撃対象領域です。その分類と対策をまとめました。

8 分で読める

Ralphループ:自律型AIエージェントを一晩中稼働させる方法

ストップフック、スポーンバジェット、ファイルシステムメモリを備えた自律エージェントシステムを構築しました。失敗から学んだことと、実際にコードをシップする仕組みを紹介します。

11 分で読める