あなたのエージェントには信頼できない入力が二つある
従来のプログラムには信頼境界が一つあります。ユーザーが渡す入力です。その境界で検証すれば、おおむね終わりです。エージェントはひそかに境界を二つ増やしましたが、エージェントの周りに作られたツールの大半は、そのうち一つしか本物として扱っていません。
一つ目の新しい入力は、モデルが書き、あなたのプロセスが実行するコードです。二つ目は、モデルが読み、それに基づいて行動するツール出力です。どちらもあなたの制御下にない場所、つまり言語モデルのサンプリング分布か、第三者のサーバーからあなたのシステムに入ってきて、どちらも到着した瞬間に信頼されたものとして扱われます。いまエージェントのセキュリティが落ち着かないと感じられるのは、業界が一つ目の入力には信頼に足る答えを持っていながら、二つ目も同じ問題であるかのように振る舞い続けているからです。同じ問題ではありません。
要点
- エージェントには信頼できない入力が一つではなく二つあります。 ランタイムが実行するモデル生成コードと、モデルが取り込んで行動するツール/サーバー出力です。両者は異なる形で失敗し、異なる防御を必要とします。両者を混同することこそ、サンドボックスの中にいると感じながら攻撃可能なままでいる理由です。12
- 信頼できないコードの実行には、ついに信頼に足る隔離の答えができました。 Simon Willisonの
micropython-wasmは、モデルが書いたPythonを、メモリとCPUの制限、制御されたファイルおよびネットワークアクセスを備えたWebAssemblyサンドボックスの中で実行します。本物のサンドボックスに必要な特性を、「ブラウザで10年近く試されてきた」基盤の上で備えたものです。1 - ツールポイズニングはコード実行の問題ではないので、コードサンドボックスは何の役にも立ちません。 MCPツールの説明に隠された悪意ある指示は「ユーザーには見えないがAIモデルには見える」もので、汚染されたツールが一度も実行されなくてもエージェントを乗っ取れます。23
- もっとも深い問題は、接続時と実行時のあいだの信頼のギャップです。 ツールの説明は承認時に一度だけ審査されます。ツールの応答は同等の検査なしにモデルのコンテキストへ直接流れ込み、悪意あるサーバーは承認後に説明を変更できます。2
二つの入力、二つの失敗モード
二つの入力を並べて見てください。非対称性こそが要点のすべてだからです。
モデルがコードを書き、あなたがそれを exec() するとき、失敗モードはコードがあなたのマシンに何かをすることです。読んではいけないファイルを読み、ソケットを開き、CPUを永遠に回し、状態を壊す。爆発半径はあなたのプロセスと、それが到達できるすべてです。防御は古くからあり、よく理解されています。隔離です。重要なものに触れられない場所でコードを実行することです。
モデルがツール出力を読んでそれに基づいて行動するとき、失敗モードはその言葉がモデルの決定を変えることです。古典的な意味であなたのホスト上で実行されるものは何もありません。代わりに、「データ」として届いたテキストが「指示」として解釈され、あなたの認証情報を握ったエージェントがそれを実行します。爆発半径は、あなたのエージェントが行うことを許可されているすべてです。プロセスの隔離をどれだけ施しても役に立ちません。エージェントはそもそもそのツールを読み、それに基づいて行動できるはずだったのですから。エクスプロイトは正規の経路に乗ってやってきます。
コードサンドボックスは一つ目の入力を囲む壁です。必要なものであり、ついに良くなってきています。そして二つ目の入力については完全に沈黙しています。
ついにサンドボックスを得た入力
2026年6月6日、Simon Willisonはmicropython-wasmを公開しました。WebAssemblyサンドボックスでPythonを実行するアルファ版パッケージで、何年もしっくりこないアプローチを試した末のものです。1 動機はまさに一つ目の信頼できない入力です。彼は自身のDatasette Agentの中で、ホストを危険にさらすことなくLLMが生成したコードを実行したいのであり、彼の言葉を借りれば「バグのある、あるいは悪意あるプラグインは、すべてを壊したりプライベートなデータを漏らしたりしかねない」からです。1
注目に値するのは、それが実際に満たしているチェックリストです。そのチェックリストこそが、使えるサンドボックスの定義だからです。
- メモリとCPUの制限。 モデルが書いた
while True: s += "x"がホストを枯渇させることはできません。CPUはwasmtimeの「fuel」機構で制限されており、Willisonはその単位が「推論しにくい」と正直に述べています。1 - 制御されたファイルおよびネットワークアクセス。 デフォルトで開くのではなく、デフォルトで拒否です。
- クリーンな隔離モデル。 コードはリクエスト/リプライのキューの背後にある別スレッドで実行され、WASMインタープリタは仕事を渡されるまでホスト関数でブロックします。そのため信頼できないコードがホストのアドレス空間を共有することはありません。1
- 実績のある基盤。 彼がWebAssemblyを選んだのは、それが「最初から私が重視する特性のすべてをサポートするよう設計され、ブラウザで10年近く試されてきた」からであり、MicroPythonを選んだのは、ブラウザ向けのPyodideがサーバーサイドではサポートされていないからです。1
その正直さこそ、良いセキュリティの仕事のしるしです。Willisonはこれをアルファ版として出し、「相当なリスクを引き受ける気のない人には勧められる状態ではない」と書いています。1 それがエビデンス・ゲートの姿勢です。検証したことだけを正確に主張し、それ以上は主張しない。要点はこの一つのパッケージが答えだということではありません。信頼できないコードに対する答えの形が、いまや明確で再現可能になったということです。リソース制限とデフォルト拒否のI/Oを備えた、本物の隔離境界です。一つ目の入力は、解決済みのエンジニアリング問題になりつつあります。
罠は、それを解決すれば安全になると信じることです。
サンドボックスのない入力
二つ目の入力はコードを実行しないので、壁は何の役にも立ちません。2025年4月1日、Invariant Labsはツールポイズニング攻撃を公開しました。「悪意ある指示がMCPツールの説明の中に埋め込まれ、ユーザーには見えないがAIモデルには見える」というものです。2 非対称性がそのままエクスプロイトです。「AIモデルは隠された指示を含む完全なツールの説明を見るのに対し、ユーザーは通常、UIで簡略化された版しか見ない」のです。2 UIでは「二つの数を足す」と読めるツールが、モデルが実際に消費する説明の中では、~/.ssh/id_rsa を読んで隠しパラメータ経由で流出させろという指示を運んでいることがありえます。2 OWASPはいま、これを名前のついた攻撃クラスとして分類しています。3
隔離では届かない形でこれを厄介にしている性質が二つあります。
ツールが呼び出されなくても発動します。 汚染された指示は説明の中に住んでいて、モデルはツールセットを検討するときにそれを取り込みます。だから関数が一度も実行されなくても攻撃は成立しうるのです。3 サンドボックスに入れるべきコードのイベントがありません。
信頼は一度付与され、あとで悪用されます。 ツールの説明は、サーバーを承認する接続時に審査されます。その後、応答は実行時に同等の検査なしにモデルのコンテキストへ直接流れ込みます。そしてInvariantの「ラグプル」の発見によれば、「悪意あるサーバーはクライアントがすでに承認したあとでツールの説明を変更できる」のです。2 あなたの一度きりの承認は、継続的なものを何も守ってくれません。
代表的な実証は仮説ではありません。研究者たちはGitHubのissueに注入テキストを仕込みました。開発者がアシスタントに未解決のissueをレビューするよう頼むと、エージェントはそのissueを取り込み、隠された指示に従い、開発者のトークンを使ってプライベートリポジトリを読み、その内容を公開プルリクエストに漏らしました。3 個々のアクションはすべて許可されたものでした。エージェントはまさにエージェントがするべきことをしたのです。だからこそ、ここではコードサンドボックスは無関係です。信頼できないものが実行されたのではなく、信頼できないテキストが、本物の認証情報を握るプロセスの中で指示へと昇格しただけなのです。Ken ThompsonがReflections on Trusting Trustに残したのと同じ教訓です。危険なのは検査するコードではなく、検査せずに差し出す信頼です。
二つ目の入力を守る
隔離がコードに対する防御であるなら、ツール出力に対する防御は、データと指示のあいだの境界を、実行時に、毎回、実在するものとして扱うことです。接続時承認モデルが飛ばしているまさにそれです。Microsoft自身のMCPガイダンスも同じ場所に着地しています。注入された指示を検出してフィルタリングする「プロンプトシールド」と、「システムメッセージに区切り文字を含めて入力テキストの位置を明示する」スポットライティングを推奨し、モデルがコンテンツとコマンドを見分けられるようにするのです。4 具体的には:
- 承認時だけでなく、実行時に説明を再確認する。 承認したツール定義を固定し、サーバーの説明が足元で変わったときに検出する。ラグプルが成功するのは、誰も二度見しないからにすぎません。2
- データ/指示の境界を明示的に示す。 ツールの応答はデータであって指令ではありません。実践的な形がスポットライティングです。コンテキストの中でツール出力を区切り、それが従うべきコマンドではなく推論の対象となるコンテンツであることを、構造的にモデルへ伝えるのです。4 これはMCPツールのアクション単位の認可と対になり、乗っ取られたエージェントでさえ、結果の重大な呼び出しには届けないようにします。
- 許可された経路に最小権限を適用する。 GitHubのエクスプロイトが成功したのは、一つのエージェントが「プライベートリポジトリの読み取り」と「公開PRの作成」の両方を握っていたからです。そして最小権限こそ、Microsoftがこうした攻撃に対する基礎的な衛生として名指しするものです。4 Joanna Rutkowskaの区画化によるセキュリティは、アーキテクチャのレベルでの同じ本能です。あるドメインが侵害されたと仮定し、それが他のドメインに届かないようにする。issueを読むエージェントが、流出経路を握るエージェントであってはなりません。
- イグレスを監視する。流出こそが見返りだからです。 これらの攻撃の大半は同じステップ、つまりデータが出ていくところで終わります。サイレントなイグレスの視点は、注入が玄関をすり抜けても、その帰結を捉えます。
これらのどれも壁ではありません。エージェントが歩くべく作られた道の上の門です。より難しく、より満足感の薄い種類のセキュリティであり、二つ目の入力が実際に要求する種類のものです。
ここから受け取るもの
私が持ち続けている心的モデルは、「私のエージェントはサンドボックス化されているか?」が間違った問いだというものです。守るべき境界が一つだと暗黙に仮定しているからです。境界は二つあります。私のモデルが書くコードには壁が必要で、Willisonのような仕事のおかげで、その壁を築くことは明確な仕様を持つ通常のエンジニアリング作業になりつつあります。私のモデルが読むツール出力には、まったく別のものが必要です。データがひそかに指示になることを決して許さないランタイムと、乗っ取られたエージェントでもたいしたことができないほど締まった認可モデルです。両者を混同することが、「ほら、コードはWASMで動いている」と守られている気になりながら、誰も門を付けなかった入力を通じて無防備なままでいる方法なのです。
より深い連続性は、エージェントが新しいカテゴリの脆弱性を発明したというより、古い脆弱性が住む新しい場所を増やしたということです。信頼できない入力は常にセキュリティの根本でした。エージェントの時代はそこに新しい扉を二つ付けただけです。一つは隔離で施錠でき、一つは規律で見張ることしかできません。壁と門を築きましょう。入力が二つあるシステムで壁だけというのは、完全な防御のように感じられる半分の防御です。
よくある質問
AIエージェントにおける二つの信頼できない入力とは何ですか?
ランタイムが実行するモデル生成コードと、モデルが読んでそれに基づいて行動するツールまたはサーバーの出力です。前者はホストを直接損傷させることができ、後者はエージェントがすでに保持している認証情報と権限を使ってエージェントの決定を乗っ取ることができます。両者には異なる防御が必要です。コードには隔離、ツール出力には実行時のデータ/指示の分離と厳格な認可です。12
コードサンドボックスはMCPツールポイズニングを防げますか?
いいえ。ツールポイズニングはあなたのホストでコードを実行しません。ツールの説明に、モデルが信頼されたものとして扱う指示を埋め込むのであり、ツールが一度も呼び出されなくても発動しえます。23 サンドボックスは実行を隔離するものなので、エージェントの正規で許可されたアクションに乗ってくる攻撃には何の役にも立ちません。
ツールポイズニング攻撃とは何ですか?
2025年4月にInvariant Labsが公開した攻撃で、「悪意ある指示がMCPツールの説明の中に埋め込まれ、ユーザーには見えないがAIモデルには見える」というものです。2 モデルは完全な説明を見るのに対し、ユーザーは簡略化されたUIラベルしか見ないため、たとえばSSH鍵を読んで流出させろといった隠された指示がエージェントを乗っ取れます。OWASPはいま、これを名前のついた攻撃クラスとして追跡しています。23
接続時と実行時の信頼のギャップとは何ですか?
ツールの説明は、サーバーを承認するとき(接続時)に一度だけ審査されます。その後、ツールの応答は実行時に同等の検査なしにモデルのコンテキストへ流れ込み、悪意あるサーバーは承認後に説明を変更できます(「ラグプル」)。2 修正は、承認時だけでなく実行時に検証することです。
出典
-
Simon Willison、「Running Python code in a sandbox with MicroPython and WASM,」 simonwillison.net、2026年6月6日。アルファ版
micropython-wasmパッケージとdatasette-agent-micropythonプラグインの紹介。「バグのある、あるいは悪意あるプラグインは、すべてを壊したりプライベートなデータを漏らしたりしかねない」という動機。サンドボックスのチェックリスト(wasmtimeの「fuel」によるメモリ/CPU制限、制御されたファイル/ネットワークアクセス、別スレッドのリクエスト/リプライ隔離)。WebAssemblyが「最初から私が重視する特性のすべてをサポートするよう設計され、ブラウザで10年近く試されてきた」という根拠。そして「相当なリスクを引き受ける気のない人には勧められる状態ではない」という注意書き。 ↩↩↩↩↩↩↩↩↩ -
Luca Beurer-KellnerとMarc Fischer、「MCP Security Notification: Tool Poisoning Attacks,」 Invariant Labs、2025年4月1日。最初の公開:「ツールポイズニング攻撃は、悪意ある指示がMCPツールの説明の中に埋め込まれ、ユーザーには見えないがAIモデルには見えるときに発生する」。可視性のギャップ(「AIモデルは隠された指示を含む完全なツールの説明を見るのに対し、ユーザーは通常、UIで簡略化された版しか見ない」)。「悪意あるサーバーはクライアントがすでに承認したあとでツールの説明を変更できる」という「ラグプル」の発見。そして
~/.cursor/mcp.jsonと~/.ssh/id_rsaを読む汚染されたaddの例。 ↩↩↩↩↩↩↩↩↩↩↩↩↩ -
「MCP Tool Poisoning,」 OWASP Foundation。ツールポイズニングを名前のついた攻撃クラスとして分類:「汚染されたツールが一度も呼び出されなくても」エージェントに影響するツールメタデータ内の隠された指示、そして汚染されたissueがエージェントに開発者のトークン経由でプライベートリポジトリを読ませ、公開プルリクエストに漏らさせるGitHub MCPの例。 ↩↩↩↩↩↩
-
Sarah YoungとDen Delimarsky、「Protecting against indirect prompt injection attacks in MCP,」 Microsoft Developer Blog、2025年4月28日。「高度な機械学習アルゴリズムと自然言語処理を使って悪意ある指示を検出しフィルタリングする」「プロンプトシールド」、「システムメッセージに区切り文字を含めて入力テキストの位置を明示する」スポットライティング、MCPコンポーネントのサプライチェーン検証、そして最小権限のような基礎的な衛生を推奨。 ↩↩↩