Security 2026年8月28日

第5回 MCP と外部連携 — 非信頼な入力がツールを動かす経路を塞ぐ

lethal trifecta(機密データ・非信頼コンテンツ・外部通信)を設計の採点表として使い、MCP 公式が MUST/MUST NOT で定めるトークン転送禁止・Confused Deputy・SSRF・スコープ最小化への対処と、実際に報告された MCP の脆弱性から実務の判断基準を組み立てます。

難易度基本的な操作を一度試したことがある前提です種別学習コース

この回のキーメッセージ

プロンプトインジェクションは防ぎきれない前提で、機密データ・非信頼コンテンツ・外部通信の3つが同じセッションに揃わないよう設計します。

第2回から第4回までは、エージェント本体の権限とガードレールを扱いました。ここからは外側、つまり MCP サーバーや Web fetch を通じて外部とつながる部分を見ます。権限設定を丁寧に詰めても、エージェントが読み込んだ外部テキストの中に指示が混ざっていれば、その指示は「許可済みの権限の範囲内で」実行されます。権限設計だけでは塞げない経路がここにあります。

プロンプトインジェクションそのものの説明は、利用者向けに 生成物と外部入力 で扱っています。本記事は繰り返さず、実装者が構成を決めるときの判断材料に絞ります。MCP の仕様やサーバーの追加手順は Claude Code MCPガイド、どのサーバーを入れるかの選定は MCPサーバー選定と最適化 を参照してください。

前提として押さえておきたいのは、この問題に「対策を入れれば解決する」形の解がないことです。入力の検証で弾けるのは既知の形だけで、自然言語には無限の言い換えがあります。そのため設計側は、攻撃が成功しても被害が成立しない構成を選ぶ方向に寄せます。その判断の道具になるのが、次に扱う整理です。

1. lethal trifecta を採点表として使う

Simon Willison が2025年6月に提唱した整理で、次の3要素が同時に揃ったときに危険が成立するとしています。

要素中身具体例
機密データへのアクセスエージェントが盗まれて困るものを読めるソースコード、.env、DB、社内ドキュメント、メール
非信頼コンテンツへの露出第三者が中身を書ける文字列がコンテキストに入るWeb ページ、Issue やPR のコメント、受信メール、外部 API のレスポンス、依存パッケージの README
外部への通信能力読んだ内容を外へ出せるHTTP リクエスト、Slack や メールの送信、リモートへの git push、外部 URL を含む画像参照

3つが揃うと、攻撃者は非信頼コンテンツに指示を書き込むだけで、機密データを自分の手元へ送らせることができます。メモリ破壊もサンドボックス脱出も不要で、エージェントは許可された機能を使って指示どおりに動くだけです。逆に言えば、2つまでなら同じ攻撃は成立しません。設計とは、3つのうちどれか1つを外すことです。

自分のセットアップを採点する

構成を決めたら、その場で3列に印を付けます。

セットアップ例機密データ非信頼コンテンツ外部通信判定
ローカルの private リポジトリで、Web fetch と外部連携なしのコード修正ありなしなし1/3
公開ドキュメントを読ませて要約させるだけ(リポジトリ非接続)なしありあり2/3
GitHub MCP(private リポジトリ)+ Web fetch + Slack 通知ありありあり3/3
GitHub MCP(private)+ 外部 Issue のコメントを読む + ネットワーク遮断サンドボックスありありなし2/3
CI 上で外部 PR の差分をレビューさせ、結果をコメント投稿するありありあり3/3

注意したいのは、3つ目の列が思ったより埋まりやすいことです。「外部通信」は明示的な HTTP ツールだけを指しません。エージェントがコードを実行できるなら、その実行経路が通信手段になります。Markdown 出力に外部ホストの画像 URL を書けるなら、レンダリング時にクエリ文字列として情報が出ていきます。「非信頼コンテンツ」も同様で、自分で書いたコードしか読ませていないつもりでも、node_modules の中身や、エージェントが取得したエラーメッセージの本文は第三者由来です。

採点で 3/3 になったら、次のどれかで1つ落とします。

  • 機密データを外す: 対象リポジトリを絞る、.env や鍵ファイルを deny 指定で読めなくする(第2回の権限設計)
  • 非信頼コンテンツを外す: 外部フェッチを禁止する、要約は別セッションに分ける
  • 外部通信を外す: サンドボックスのネットワークを遮断する、書き込み系 MCP ツールを外す

どれも落とせない作業は、無人実行にしないという判断になります。

2. MCP 公式が MUST / MUST NOT で書いていること

MCP の公式ドキュメントには、セキュリティベストプラクティスとして具体的な攻撃と対策が列挙されています。ここでは実務で効く5点を取り上げます。

Token Passthrough は禁止(MUST NOT)

MCP サーバーが、自分宛てに発行されたのではないトークンを検証せずに下流の API へ転送することは、明示的に禁止されています。audience(そのトークンが誰宛てか)の検証を省くと、次の3つが同時に壊れます。

  • 制御の迂回: 下流 API 側のレート制限や利用制限が、MCP サーバー経由で回避される
  • 監査の断絶: 下流のログに MCP サーバーの識別子が残らず、誰が呼んだか追えなくなる
  • 信頼境界の崩壊: 「このトークンは自分宛て」という前提が成立しなくなり、以降の認可判断が無意味になる

自作サーバーを書くときは、受け取ったトークンをそのまま Authorization ヘッダに詰め替えて転送していないかを最初に確認します。

Confused Deputy

静的な client_id、動的クライアント登録、consent(同意)cookie が組み合わさると、攻撃者が正規ユーザーの consent cookie を利用して MCP の認可コードを窃取しうる、という問題です。対策として次が挙げられています。

  • クライアントごとの consent(一度同意すれば全クライアントに通る、という設計にしない)
  • consent cookie に __Host- prefix、SecureHttpOnlySameSite=Lax を付ける
  • redirect_uri を前方一致ではなく厳密一致で検証する
  • state パラメータを暗号学的に検証する

SSRF

OAuth のメタデータ探索時などに、内部 IP(192.168.x.x など)やクラウドのメタデータエンドポイント(169.254.169.254)を指す URL を注入されうる、という指摘です。対策は HTTPS の強制、プライベート IP レンジのブロック、リダイレクト先の再検証、egress proxy の経由、DNS rebinding 対策です。

公開されている MCP インスタンスのうち相当数が認証なしのリクエストに応答した、SSRF に脆弱な可能性のあるサーバーが一定割合あった、といった調査報告もあります。これらは二次情報なので数字を鵜呑みにはできませんが、少なくとも「MCP サーバーは外向きに立てた時点で普通の Web サービスと同じ攻撃面を持つ」ことの裏付けにはなります。

ローカル MCP サーバーの侵害

ローカルで動く MCP サーバーは、MCP クライアントと同一の権限で任意コードを実行できます。公式ドキュメントは、悪意ある起動コマンドの例として SSH 秘密鍵を外部へ送信するものや、再帰削除で破壊するものを挙げています。つまり、設定ファイルに1行足すというワンクリック導入は、実質的にはローカルで任意のバイナリを実行することと同じ重さを持ちます。対策として、ワンクリック設定時の明示的な同意、サンドボックス化、stdio transport の利用制限が挙げられています。

スコープ最小化

files:*db:*admin:* のような広範なスコープを最初に一括で付与すると、トークンが漏れたときの被害範囲がそのまま最大になります。公式は段階的なスコープ昇格モデルを推奨しており、不足時に WWW-Authenticatescope= チャレンジで必要な分だけ追加する形を示しています。実務上は「足りない状態から始めて、詰まったら足す」という運用に落ちます。

3. 書く側と使う側で、見る項目が違う

同じ MCP でも、自分でサーバーを実装する場合と、他人のサーバーを導入する場合では確認すべき項目が別物です。

観点自分で MCP サーバーを書く場合他人の MCP サーバーを使う場合
トークンaudience を検証し、転送しない。自分宛てでないトークンは拒否するトークンをどこへ送るサーバーか。認証情報の保存場所はどこか
認可per-client consent、redirect_uri の厳密一致、state の検証要求されるスコープの広さ。read-only 版が提供されていないか
ネットワークプライベート IP とメタデータエンドポイントをブロック。egress を絞るサーバーがどこへ通信するか。ソースが公開されているか
実行権限外部入力をシェルへ渡さない。パス検証は正規化後に行うローカル実行かリモートか。ローカルなら自分と同じ権限で動く前提で見る
ツール定義説明文にモデルへの過剰な指示を書かない。副作用のあるツールは名前で分かるようにするツールの説明文自体が非信頼コンテンツになりうる(tool poisoning)
更新破壊的変更の周知経路を持つバージョンを固定しているか。更新時に説明文の差分を見るか

最後の行は見落とされがちです。MCP サーバーのツール定義は、モデルのコンテキストに文字列として入ります。サーバー側が説明文を書き換えれば、それはエージェントへの新しい指示になります。MCP サーバーの追加は、依存パッケージの追加と同じ重さで扱います(サプライチェーンの観点は第11回で扱います)。

4. 公式が出しているものでも脆弱性は出る

抽象論で終わらせないために、実際に報告された事例を挙げます。いずれも修正済みで、煽る意図はありません。読み取りたいのは傾向のほうです。

事例内容
Anthropic 公式 Git MCP サーバー(CVE-2025-68143 / 68144 / 68145、2025年12月に修正版リリース、2026年1月に一般公表)パス検証のバイパス、無制限の git_initgit_diff での引数注入。プロンプトインジェクションと連鎖することで RCE やファイル上書きに至りうるとされた
mcp-remote(CVE-2025-6514、CVSS 9.6)OS コマンドインジェクション。非信頼なリモート MCP サーバーへ接続した際に、クライアント OS 上でのフル RCE に至る
Azure DevOps MCP(CVE-2026-32211、CVSS 9.1)@azure-devops/mcp における認証の欠如
MCPoison(CVE-2025-54136)/ CurXecute(CVE-2025-54135)Cursor IDE の MCP 設定ファイルをめぐる自動実行と承認バイパス。ツール定義そのものを汚染する手口とは機序が異なるが、MCP の信頼境界が破られた事例として重要

ここから読み取れることは3つあります。

  1. 「公式が出しているサーバーだから安全」は成り立ちません。 プロトコルの提唱元が出したサーバーにも脆弱性は出ました。出所の確認は必要条件であって十分条件ではありません。
  2. 単体では軽微な欠陥が、プロンプトインジェクションと連鎖して致命傷になります。 引数注入だけなら攻撃者は引数を制御する経路が要りますが、エージェントが非信頼コンテンツを読むなら、その経路は既に存在します。
  3. 仲介レイヤーが増えるほど攻撃面が増えます。 mcp-remote のようなブリッジは、それ自体が信頼境界になります。

運用側の帰結としては、MCP サーバーのバージョンを固定し、依存として棚卸しの対象に入れ、CVE を追う対象として扱うことになります。導入した日に安全でも、その状態は続きません。

5. モデル側の対策に寄りかからない

Anthropic は、プロンプトインジェクションへの緩和策として次を公表しています。

  • 強化学習によって、インジェクション耐性をモデルの能力として組み込む。シミュレートされた Web コンテンツ埋め込み攻撃を識別・拒否するよう訓練する
  • 分類器ですべての非信頼コンテンツをスキャンし、隠しテキストや操作画像を含む複数形態の攻撃をフラグする
  • 社内のセキュリティ研究者による継続的な脆弱性調査と、業界ベンチマークへの参加

同時に、公式はブラウザ操作(Claude for Chrome)の内部評価で攻撃成功率が1%残っており、問題が解決したわけではないと明言しています。この1%はブラウザ操作の測定値であって MCP 全般の数値ではありませんが、「対策を入れてもゼロにはならない」という前提として読む価値があります。

人間が1回ずつ確認しながら使う場面では、1%は許容できる水準かもしれません。しかし自動実行では話が変わります。1日100回エージェントを回す運用なら、計算上は1日1回通ります。週次のバッチが52回動けば、年内に通る確率のほうが高くなります。試行回数が増えるほど、モデル側の防御は当てにできなくなります。 無人実行の頻度が高い構成ほど、モデルの外側で trifecta を崩しておく必要があります。

6. 実務の設計指針

ここまでを構成の判断に落とすと、次の5点になります。

非信頼コンテンツを読むセッションでは、書き込みと外部通信を切る。 調査・要約と、コードの変更・デプロイを同じセッションに同居させません。セッションを分けるだけで、trifecta の1つが自然に落ちます。

MCP サーバーの追加は依存パッケージの追加と同じ手続きで行う。 ソースの確認、バージョン固定、棚卸し台帳への記載、更新時の差分確認までをセットにします。「試しに入れてみる」を本番の設定ファイルで行わないという意味でもあります。

スコープは足りない状態から始める。 read-only 版があるならまずそれを入れます。書き込みが要ると分かった時点で、必要なリソースに限って広げます。逆方向(広く付けてから絞る)は、実際には絞られません。

無人実行では trifecta を必ず1つ外す。 CI やスケジュール実行では人間の確認が挟まらないため、構成そのもので成立を防ぎます。外部由来の差分をレビューさせるなら、認証情報を持たせない、あるいは結果の投稿先を固定して任意の外部通信を許さない、といった形にします。

エージェントの出力を、そのまま次の実行の入力にしない。 非信頼コンテンツを読んだセッションの出力は、それ自体が非信頼になります。パイプラインで繋ぐときは、人間の確認か、機械的に検証できる形式(決まったスキーマの JSON など)を境界に置きます。

Hooks で機械的に止める方法は第4回、権限そのものの設計は第2回で扱っています。本記事の指針は、それらを「どう組み合わせるか」を決めるための上位の判断軸として使えます。

まとめ

  • lethal trifecta(機密データ・非信頼コンテンツ・外部通信)が3つ揃うと、攻撃者は非信頼コンテンツに指示を書くだけでデータを持ち出せる。2つまでなら成立しない
  • 構成を決めたら3列で採点し、3/3 なら必ず1つ落とす。外部通信は明示的な HTTP ツール以外にも潜む
  • MCP 公式はトークン転送の禁止(MUST NOT)、per-client consent、SSRF 対策、スコープ最小化を具体的に定めている。自作する側と使う側で見る項目は別物
  • 公式提供の MCP サーバーにも脆弱性は出た。出所の確認は必要条件にすぎず、バージョン固定と CVE 追跡が要る
  • モデル側の耐性には限界があると公式が明示している。試行回数の多い無人実行では、構成側で trifecta を崩しておく

参考リンク