第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、Secure、HttpOnly、SameSite=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-Authenticate の scope= チャレンジで必要な分だけ追加する形を示しています。実務上は「足りない状態から始めて、詰まったら足す」という運用に落ちます。
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_init、git_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つあります。
- 「公式が出しているサーバーだから安全」は成り立ちません。 プロトコルの提唱元が出したサーバーにも脆弱性は出ました。出所の確認は必要条件であって十分条件ではありません。
- 単体では軽微な欠陥が、プロンプトインジェクションと連鎖して致命傷になります。 引数注入だけなら攻撃者は引数を制御する経路が要りますが、エージェントが非信頼コンテンツを読むなら、その経路は既に存在します。
- 仲介レイヤーが増えるほど攻撃面が増えます。 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 を崩しておく
参考リンク
- The lethal trifecta for AI agents(Simon Willison) — 3要素の整理の原典
- MCP Security Best Practices(modelcontextprotocol.io) — Token Passthrough 禁止、Confused Deputy、SSRF、スコープ最小化の一次ソース
- Mitigating prompt injection attacks(Anthropic) — 緩和策と、ブラウザ操作における残存成功率の明示
- Anthropic patches Git MCP server flaws(The Register) — CVE-2025-68143 / 68144 / 68145 の報道
- MCP supply chain advisory(ox.security) — mcp-remote ほかエコシステム横断の脆弱性報告