FlawOpen

flawopen.com/Teardowns/cve-2026-97662-aws-security-agent-mcp-git-argument-injection

● CVE-2026-97662 · CVSS v4 6.9 · Средний
Исследования · FlawOpen

CVE-2026-97662: внедрение аргументов Git в AWS Security Agent MCP

CVE-2026-97662 позволяла трактовать управляемую вызывающей стороной ссылку Git в diff scan AWS Security Agent MCP как параметр команды. Это обходило ограничение workspace и позволяло записывать файлы на хосте. Обновитесь до версии 0.2.0 или новее.[1], [2]

Вектор CVSSCVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N
💡 Простыми словами (ELI5)

Сотруднику дают найти папку по ярлыку, но он принимает ярлык, начинающийся с управляющей команды. Архивная система выполняет команду вместо поиска папки. Здесь ссылка Git с начальным дефисом могла восприниматься как опция. Проверка и отклонение пустых ссылок и строк, похожих на опцию, до запуска Git закрывает этот вход. Речь идёт о разборе параметров Git, а не о произвольном выполнении команд оболочки.[2]

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

MCP-сервер
Локальный процесс, предоставляющий инструменты приложению ИИ через Model Context Protocol. Аргументы инструментов поступают в сервер как недоверенные данные.
Внедрение аргументов (CWE-88)
Программа командной строки воспринимает недоверенный ввод как опцию или разделитель, даже если процессу передан массив аргументов, а не строка оболочки.[2], [4]
Ссылка Git
Имя или выражение, обозначающее коммит или дерево, например main или HEAD~1. Значение с начальным - может быть разобрано как опция.[2], [3]
Ограничение workspace
Граница, призванная удерживать файловые операции инструмента в выбранном каталоге проекта. Она неполна, если ввод меняет смысл команды подпроцесса.[1], [3]

Связи со стандартами

Анализ первопричины

AWS описывает контекстное внедрение аргументов в операции diff scan: переданная ссылка могла интерпретироваться как параметр командной строки, а не как ревизия Git. Upstream PR подтверждает, что start_diff_scan передавал base_ref командам git diff <base_ref> -- и git archive; пустые значения и значения с начальным дефисом могли трактоваться иначе. Это не внедрение метасимволов оболочки: список аргументов исключает разбор оболочкой, но вызываемая программа всё ещё может распознать опцию. Согласно AWS, это позволяло создавать, перезаписывать или обрезать файлы за пределами заданного workspace в рамках прав процесса. Влитое исправление проверяет base_ref до вызова Git и отклоняет пустые значения и значения, обрезанный текст которых начинается с -; тесты подтверждают отсутствие подпроцесса и загрузки при отклонённом вводе. Уязвимы версии >=0.1.1 и <0.2.0; версия 0.2.0 содержит исправление. В записи CVE указана оценка CVSS 4.0 6,9 (средняя); GitHub Advisory также приводит CVSS 3.1 8,2 (высокая). Эксплойт-полезная нагрузка здесь не воспроизводится.[1], [2], [3], [4]

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

Шаг 1

Агент вызывает diff scan

Локальный MCP-сервер получает base_ref, на который может влиять вызывающая сторона. Риск возникает, если недоверенный репозиторий, содержимое или пользователь могут задавать это значение; prompt injection сама по себе не достигает этот путь автоматически.[2]

Шаг 2

Значение попадает в Git как позиционный аргумент

Уязвимый код передаёт ссылку командам Git diff и archive. Начальный дефис может заставить Git разобрать её как опцию, даже если Python не использует оболочку.[2], [3]

Шаг 3

Разбор опций Git нарушает предполагаемую границу

Подходящая для этого контекста опция может перенаправить запись за пределы workspace. Описанный эффект — создание, перезапись или обрезка доступных процессу файлов; масштаб зависит от прав и сценария.[1], [3]

Шаг 4

Отклоняйте опасные ссылки до побочных действий

Версия 0.2.0 проверяет base_ref до Git, загрузки в S3 и проверки пространства агента. Обновите сервер и запускайте его с минимальными правами в изоляции.[1], [3], [6]

Трассировка границы: имя ревизии и параметры Git

Концептуальный поток данных, а не последовательность команд или воспроизведение эксплойта.

Два парсера — две отдельные границы

Разбор оболочкой
Массив аргументов не позволяет оболочке трактовать значение как её синтаксис и закрывает эту границу.[3]
Разбор параметров Git
Git по-прежнему разбирает собственный синтаксис командной строки. Массив не мешает трактовать контролируемую вызывающей стороной ревизию как параметр; проверяйте её до вызова Git.[2], [3]
1

Вызывающая сторона влияет на ревизию

Инструмент diff scan получает base_ref из рабочего процесса. Риск возникает только тогда, когда недоверенный источник может повлиять на это значение.[2], [3]

2

Массив аргументов всё равно попадает в разбор Git

Python может передавать значения отдельно и исключить обработку оболочкой, но Git всё равно разбирает собственные параметры командной строки.[3], [2]

3

Предположение об изоляции workspace может нарушиться

Если Git распознает значение как параметр, запись файлов может выйти за пределы заданного workspace; её ограничивают права процесса MCP в ОС.[1], [2]

4

Проверка закрывает границу ввода

Версия 0.2.0 отклоняет пустые и похожие на параметры ревизии до запуска Git и других побочных действий. Ввод больше не задаёт поведение параметров Git; допустимые ревизии по-прежнему выбирают запрошенную ревизию.[3], [6]

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

Это целевое сравнение точки вызова upstream, а не полный листинг сканера. Влитое изменение проверяет ссылку до Git; тесты проверяют пустые и начинающиеся с дефиса значения без подпроцесса и загрузки. Массив аргументов предотвращает разбор оболочкой, но не разбор опций самим Git. В этом фрагменте показан только вызов git diff; та же проверка должна защищать каждое использование base_ref, в том числе в git archive.[3]

УЯЗВИМАЯ РЕАЛИЗАЦИЯ
def start_diff_scan(path: str, base_ref: str):
    # Похожая на параметр ссылка попадает в Git до проверки.
    return subprocess.run(
        ["git", "diff", base_ref, "--"],
        cwd=path,
        check=False,
    )
БЕЗОПАСНЫЙ ИСПРАВЛЕННЫЙ ВАРИАНТ
def _validate_git_ref(base_ref: str) -> None:
    if not base_ref or not base_ref.strip():
        raise ValueError("base_ref must not be empty.")
    if base_ref.strip().startswith("-"):
        raise ValueError("base_ref must not start with '-'.")

def start_diff_scan(path: str, base_ref: str):
    _validate_git_ref(base_ref)  # Отклоняйте значение до запуска подпроцессов или загрузки файлов.
    return subprocess.run(
        ["git", "diff", base_ref, "--"],
        cwd=path,
        check=False,
    )

Чек-лист по защите системы для инженеров

Источники