AIエージェント入門

MCPサーバー脆弱性レポート2026|7千台調査で36.7%にSSRF発見

MCPサーバー脆弱性レポート2026|7千台調査で36.7%にSSRF発見

この記事の結論

BlueRock SecurityがMCPサーバー7,000台以上を調査した結果、36.7%にSSRF脆弱性が発見されました。SSRF攻撃の仕組み、AWSクレデンシャル漏洩リスク、安全な実装方法をコード例つきで解説します。

MCPサーバーのセキュリティ問題が、想像以上の速さで現実の脅威になっている。

セキュリティ企業BlueRock Securityが2025年末から2026年初頭にかけて7,000台以上のMCPサーバーを調査したところ、36.7%にSSRF(Server-Side Request Forgery)脆弱性が存在するという結果が出た。きっかけはMicrosoftのMarkItDown MCPサーバーに発見された致命的な欠陥で、悪用されるとAWSアカウントへの完全アクセスすら奪われる可能性がある。

MCPはAIエージェントのデファクトスタンダードになりつつある。それだけに、この統計は開発者として無視できない。この記事では、SSRF脆弱性の仕組みを技術的に解説し、安全なMCPサーバーの実装方法をPythonとNode.jsのコード例とともに紹介する。

何が起きたのか——MarkItDown SSRFとその波及

MicrosoftのMarkItDown MCPサーバーは、URLやファイルパスを受け取ってMarkdown変換を行うツールだ。問題は、このURIに対して一切のバリデーションが行われていない点にある。

BlueRockの研究者David Onwukweが指摘したとおり、「URIに境界がないため、ツールを呼び出すユーザー、エージェント、あるいは攻撃者であっても任意のhttpまたはファイルリソースにアクセスできる」。

具体的には次のような攻撃シナリオが成立する。

攻撃ステップ 内容 影響
1. SSRF発動 http://169.254.169.254/latest/meta-data/にリクエスト AWSインスタンスメタデータ取得
2. IAMロール確認 メタデータからIAMロール名を取得 ロール権限の把握
3. クレデンシャル窃取 一時的AWSキー(Access Key + Secret + Token)を取得 AWSアカウントへのアクセス
4. 権限昇格 取得したキーでS3/EC2/IAM等を操作 最悪、アカウント完全乗っ取り

これはMarkItDownだけの問題ではない。BlueRockの調査では、7,000台以上のMCPサーバーのうち36.7%が同様の脆弱性クラスを持つことが判明した。Anthropicの公式Git MCPサーバーにも3件のCVE(CVE-2025-68143, CVE-2025-68144, CVE-2025-68145)が発見されており、MCPエコシステム全体の問題といえる。

MCPサーバーの構築方法や基本概念については、MCPサーバー実践10選でまとめているので、あわせて参照してほしい。

SSRF脆弱性とは——5分で理解する仕組み

SSRF(Server-Side Request Forgery: サーバーサイドリクエストフォージェリ)は、アプリケーションを踏み台にして内部ネットワークや外部サービスに不正なリクエストを送らせる攻撃手法だ。

通常、クラウドの内部エンドポイント(169.254.169.254)はインターネットから直接アクセスできない。しかし、MCPサーバーがEC2上で動作していれば、MCPサーバー自身はそのエンドポイントに到達できる。攻撃者はMCPツールを呼び出してこのアドレスをURIとして渡すだけでよい。

# 攻撃者がMCPクライアント経由で送る悪意のある入力例
# 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。
# これは攻撃パターンの理解用コードです

malicious_uri = "http://169.254.169.254/latest/meta-data/iam/security-credentials/"

# MCPサーバーがバリデーションなしでこれをリクエストすると
# AWSの一時クレデンシャルが応答として返ってくる

BlueRockはこれを「氷山問題」と呼んでいる。セキュリティチームはプロンプト層のリクエストに注目しがちだが、エージェントが実際にリソースへアクセスし、ファイルを読み、権限昇格を試みるランタイム層のリスクを見落としやすい、という指摘だ。

まず試したい——安全なMCPサーバー実装3パターン

脆弱性の根本原因は「入力のバリデーション不足」だ。以下に、すぐ実装できる3つの防御パターンを示す。

パターン1: URIホワイトリストバリデーション(Python)

許可するドメインをホワイトリストで管理し、それ以外のリクエストを全て拒否する基本的なアプローチ。

import urllib.parse
from typing import Optional

# 動作環境: Python 3.11+
# 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

ALLOWED_SCHEMES = {"https"}
ALLOWED_DOMAINS = {
    "docs.example.com",
    "api.example.com",
    # 必要なドメインのみを追加
}

# AWS IMDSv1へのアクセスをブロック(特に重要)
BLOCKED_HOSTS = {
    "169.254.169.254",  # AWS Instance Metadata Service
    "metadata.google.internal",  # GCP Metadata
    "169.254.169.254",  # Azure IMDS
    "localhost",
    "127.0.0.1",
}

def validate_uri(uri: str) -> Optional[str]:
    """
    URIをバリデーション。安全なURIのみ返す、それ以外はNoneを返す。
    """
    try:
        parsed = urllib.parse.urlparse(uri)
    except Exception:
        return None

    # スキームチェック
    if parsed.scheme not in ALLOWED_SCHEMES:
        return None

    # ホスト名チェック(ブロックリスト)
    hostname = parsed.hostname or ""
    if hostname in BLOCKED_HOSTS:
        return None

    # IPアドレスの直接指定をブロック(169.x.x.x, 10.x.x.x等)
    import ipaddress
    try:
        ip = ipaddress.ip_address(hostname)
        if ip.is_private or ip.is_link_local or ip.is_loopback:
            return None
    except ValueError:
        pass  # ホスト名はIPではない(正常)

    # ホワイトリストチェック
    if hostname not in ALLOWED_DOMAINS:
        return None

    return uri


# MCPツール実装例
def convert_to_markdown_safe(uri: str) -> str:
    safe_uri = validate_uri(uri)
    if safe_uri is None:
        raise ValueError(f"URI '{uri}' is not allowed")
    # 安全なURIのみ処理する
    return fetch_and_convert(safe_uri)

ポイント: IPアドレスのprivate/link-local範囲をライブラリ(ipaddress)で判定することで、`169.254.x.x`系のバイパスを防げる。手動の文字列マッチングだけでは`0x6f6f6f6f`のような十六進数表現でのバイパスが成立することがある。

パターン2: Node.jsでのSSRF対策(URL validation)

Node.js環境では`whatwg-url`と`is-ip`を組み合わせて同様の防御を実装できる。

// 動作環境: Node.js 20+
// 必要パッケージ: npm install whatwg-url is-ip ipaddr.js
// 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

import { URL } from 'url';
import ipaddr from 'ipaddr.js';

const ALLOWED_SCHEMES = new Set(['https:']);
const ALLOWED_DOMAINS = new Set([
  'docs.example.com',
  'api.example.com',
]);

export function validateUri(uri) {
  let parsed;
  try {
    parsed = new URL(uri);
  } catch {
    throw new Error(`Invalid URI: ${uri}`);
  }

  // スキームチェック
  if (!ALLOWED_SCHEMES.has(parsed.protocol)) {
    throw new Error(`Scheme not allowed: ${parsed.protocol}`);
  }

  const hostname = parsed.hostname;

  // IPアドレスチェック
  if (ipaddr.isValid(hostname)) {
    const addr = ipaddr.parse(hostname);
    const range = addr.range();
    const blockedRanges = ['private', 'loopback', 'linkLocal', 'multicast'];
    if (blockedRanges.includes(range)) {
      throw new Error(`Private IP address not allowed: ${hostname}`);
    }
  }

  // ドメインホワイトリスト
  if (!ALLOWED_DOMAINS.has(hostname)) {
    throw new Error(`Domain not in allowlist: ${hostname}`);
  }

  return uri;
}

パターン3: MCPサーバー起動時の環境分離(Docker)

コードレベルの対策に加えて、実行環境のネットワーク分離も重要だ。

# docker-compose.yml — MCPサーバーの安全な実行環境
# 動作環境: Docker Compose v2.x
# 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

version: '3.9'
services:
  mcp-server:
    build: .
    networks:
      - mcp_restricted
    environment:
      - NO_PROXY=169.254.169.254,metadata.google.internal  # IMDS無効化
    # IMDSv1へのアクセスを完全ブロック
    extra_hosts:
      - "169.254.169.254:127.0.0.2"  # IMDSをループバックにリダイレクト

networks:
  mcp_restricted:
    driver: bridge
    driver_opts:
      com.docker.network.bridge.enable_ip_masquerade: "false"

ポイント: AWSのEC2では、インスタンスメタデータサービスv2(IMDSv2)を強制し、v1を無効化するのが最善策だ。EC2コンソールまたはAWS CLIで--metadata-options HttpTokens=requiredを設定する。

セキュリティチェックリスト——既存MCPサーバーの点検手順

既存のMCPサーバーを点検する際は、以下のチェックリストを使うとよい。

チェック項目 確認方法 対処
URIバリデーション ソースコードでURL/ファイルパスの入力点を探す ホワイトリスト実装
IMDSv1無効化(AWS) EC2コンソール > インスタンスメタデータ設定 HttpTokens=required に変更
IAMロールの最小権限 IAM > ロール > 付与された権限を確認 不要な権限を削除
外部ライブラリのバージョン pip show / npm ls で依存パッケージ確認 最新版にアップデート
ネットワーク分離 VPCセキュリティグループ、Dockerネットワーク設定を確認 必要最小限の通信のみ許可
ログとモニタリング MCPツール呼び出しのログが記録されているか CloudWatch / Datadog等でアラート設定

Anthropic公式MCPサーバーへのCVE対応

Anthropicの公式Git MCPサーバーに発見された3件のCVEについては、バージョン2025.12.18以降にアップデートすることで対処できる

# Anthropic Git MCPサーバーのアップデート
# 動作環境: npm/npx
# 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

# 現在のバージョン確認
npm list @anthropic-ai/mcp-server-git

# 最新版にアップデート
npm update @anthropic-ai/mcp-server-git

# または特定バージョンを指定(最低 2025.12.18)
npm install @anthropic-ai/mcp-server-git@2025.12.18

【要注意】よくある失敗パターンと回避策

失敗1: 「ホスト名が`169.254`で始まるかチェック」だけでは不十分

❌ 文字列の前方一致だけでブロック
ipaddressライブラリでIPの種別を判定(loopback/link-local/private全てをカバー)

なぜ重要か: 攻撃者は0xa9fea9fe(16進表現)や2852039166(10進表現)など、同じIPを別の書き方で渡してバイパスを試みる。ライブラリを使えばこれらを透過的にブロックできる。

失敗2: MCP設定ファイルにAPIキーをハードコード

claude_desktop_config.jsonにAPIキーを直書き
⭕ 環境変数(ANTHROPIC_API_KEY)を使用し、.envはGitignoreに追加

なぜ重要か: 設定ファイルがGitHubに誤ってpushされると、クレデンシャルが即座に公開される。BlueRockの調査でも、公開リポジトリ内のMCPサーバー設定からAPIキーが漏洩したケースが複数確認されている。

失敗3: サードパーティMCPサーバーを無審査で導入

❌ 公開されているMCPサーバーをそのまま本番環境に導入
⭕ コードレビュー → テスト環境検証 → 本番導入のプロセスを必ず踏む

なぜ重要か: MCPエコシステムはまだ黎明期で、公開サーバーの品質にはばらつきがある。BlueRockが運営するMCP Trust Registryでセキュリティ評価を確認することも一つの手段だ。

失敗4: 「プロンプト層」だけ監視して「ランタイム層」を放置

❌ ユーザーの入力だけをログで監視
⭕ MCPサーバーが実際に行ったHTTPリクエスト・ファイルアクセスをランタイムで記録

なぜ重要か: BlueRockが指摘する「氷山問題」そのものだ。セキュリティ侵害はプロンプト層ではなく、エージェントが実際にアクションを起こすランタイム層で発生する。

参考・出典

まとめ:今日から始める3つのアクション

  1. 今日やること: 既存MCPサーバーのコードベースで、URLやファイルパスを受け取る入力点を全て洗い出す。バリデーションがなければ、本記事のホワイトリスト実装を追加する
  2. 今週中: AWSを使っているならIMDSv2を強制有効化し、IAMロールの権限を最小限に絞る。Anthropic公式MCPサーバーはバージョン2025.12.18以降にアップデートする
  3. 今月中: MCPサーバーのランタイムログ(HTTPリクエスト・ファイルアクセス)の収集とアラート設定を導入。BlueRockのMCP Trust RegistryでサードパーティMCPサーバーの評価確認を習慣化する

あわせて読みたい:


この記事はAIgent Lab編集部がお届けしました。

関連記事: AIエージェントセキュリティ脅威2026|Q1インシデント総括と防御策

Need help moving from reading to rollout?

この記事を読んで導入イメージが固まってきた方へ

Uravationでは、AIエージェントの要件整理、PoC設計、社内導入、研修まで一気通貫で支援しています。

この記事をシェア

X Facebook LINE

※ 本記事の情報は2026年3月時点のものです。サービスの料金・仕様は変更される可能性があります。最新情報は各サービスの公式サイトをご確認ください。

関連記事