flawopen.com/Teardowns/cve-2026-105697-langflow-mcp-stdio-command-injection
CVE-2026-105697: внедрение команд MCP в Langflow
До версии 1.10.3 Langflow передавал конфигурацию MCP stdio процессу, запускаемому через оболочку. На доступном извне экземпляре с LANGFLOW_AUTO_LOGIN=true атакующий мог получить токен без учётных данных; при отключённом автоматическом входе для выполнения команд на хосте всё ещё было достаточно аутентифицированного пользователя не администратора. Версия 1.10.3 проверяет все пути, включая момент перед запуском, и запускает программу без оболочки.[1], [2], [3]
Представьте сотрудника, который получает фразу, где пунктуация может изменить задачу: один знак способен превратить указание о доставке во второй приказ. Langflow передавал настроенную команду оболочке, которая воспринимает такую синтаксическую запись как управляющую, вместо того чтобы передавать программу и аргументы как отдельные данные. Исправление проверяет разрешённую команду и запускает программу напрямую, без оболочки.[1], [2]
Ключевые понятия и термины
Транспорт MCP stdio- Запускает MCP-сервер как локальный дочерний процесс и обменивается сообщениями через стандартные потоки ввода и вывода.[1], [2]
Внедрение команд (CWE-78)- Внешне контролируемый текст изменяет команду ОС, передаваемую оболочке или средству запуска процесса.[1], [5]
Связи со стандартами
- Ссылка CWE для слабого места, описанного в этом руководстве: CWE-78
Анализ первопричины
До версии 1.10.3 конфигурация MCP stdio объединяла команду и аргументы в строку, а затем запускала её через bash -c. В версии 1.9.0 API настроек получила список разрешённых команд и проверки аргументов и окружения, однако MCP Tools, встроенные в flow или переданные через tweak, могли обойти проверку модели: на точке запуска общей политики не было. В Langflow 1.10.3 проверка сосредоточена в lfx.base.mcp.security.validate_mcp_stdio_config, применяется к API, flow, tweak, устаревшему компоненту и непосредственно перед запуском; оболочка удалена. CVE-2026-105697 относится к CWE-78, CVSS 3.1 — 9.9. Если автоматический вход отключён, атакующему всё равно нужна учётная запись не администратора с возможностью настроить или выполнить соответствующий путь MCP; включённый по умолчанию автоматический вход может открыть доступ к опубликованным тестовым экземплярам без учётных данных.[1], [2], [4], [5]
Пошаговый сценарий атаки
Пользователь достигает пути настройки MCP
В уведомлении описан доступ через настройки MCP-сервера или flow с компонентом MCP Tools. На доступном извне экземпляре с настройкой разработки LANGFLOW_AUTO_LOGIN=true атакующий мог получить токен без учётных данных. При отключённом автоматическом входе всё ещё могло быть достаточно аутентифицированного пользователя не администратора.[1]
Конфигурация поступает в подготовку процесса
Команда и аргументы формируют command_str при подготовке подключения MCP stdio.[1]
Оболочка интерпретирует строку
До 1.10.3 запуск использовал bash -c; выполнение начиналось при попытке подключения, ещё до успешного MCP handshake.[1]
Проверки на входе неполны
Версия 1.9.0 проверяет настройки REST, но конфигурации flow и tweak могут обойти проверку модели.[1]
Процесс хоста работает с правами Langflow
Команда запускается от имени пользователя службы Langflow. Интерфейс при этом может сообщить о неудачном запуске MCP-сервера.[1]
Исходный код: Уязвимый vs Защищённый вариант
Уязвимый фрагмент показывает описанный в уведомлении запуск через оболочку; это не исполняемый эксплойт. Исправленный фрагмент отражает подход версии 1.10.3: общая политика проверяет конфигурацию на каждой точке входа и повторно непосредственно перед созданием процесса, а API получает исполняемый файл и аргументы отдельно. Прямой запуск исключает интерпретацию оболочкой, но сам по себе не делает безопасными все разрешённые программы и пакеты; операторам также нужны соответствующие меры контроля источников пакетов и изоляции.[1], [2]
Фрагмент исходного кода: lfx/base/mcp/util.py — целевые фрагменты исходного кода
# Уязвимый способ запуска из уведомления (фрагмент):
server_params = StdioServerParameters(
command="bash",
args=["-c", f"exec {command_str}"],
env=env_data,
)
# Сокращённый вариант по исходному коду 1.10.3: проверить политику и запустить процесс напрямую.
command_parts = shlex.split(command_str)
if not command_parts:
raise ValueError("MCP stdio command is required")
command, args = command_parts[0], command_parts[1:]
validate_mcp_stdio_config(command, args, env_data) # Repeat at the execution boundary.
server_params = StdioServerParameters(
command=command,
args=args,
env=env_data,
) # No shell wrapper. The shared validator rejects disallowed configurations.
Чек-лист по защите системы для инженеров
- ✓Обновите
langflowдо 1.10.3+,langflow-baseдо 0.10.3+, аlfxдо 1.10.3+; проверьте версии развёрнутых пакетов.[1], [3] - ✓Не считайте REST-проверки версии 1.9.0 полным исправлением; проверьте встроенные в flow и tweak конфигурации MCP в старых версиях.[1]
- ✓Проверяйте команду, аргументы, окружение, источник пакетов и изоляцию на каждой точке входа и непосредственно перед созданием процесса.[1], [2]
- ✓Передавайте исполняемый файл и массив аргументов раздельно в API процессов; не собирайте строку для shell.[2]
- ✓В многопользовательских средах зафиксируйте разрешённые пакеты
npx/uvxи включите документированные настройки защиты интерпретатора и Docker.[1] - ✓Рекомендация FlawOpen по реагированию на инциденты: Проверьте, кто мог настраивать или запускать соединения MCP stdio во время эксплуатации уязвимых версий; изучите телеметрию хоста на предмет неожиданных дочерних процессов Langflow.[1]
- ✓Добавьте тесты REST API, flow, tweak, устаревшего компонента и pre-spawn; убедитесь, что отклонённая конфигурация не создаёт процесс.[2]