flawopen.com/Teardowns/cve-2026-105699-langflow-mcp-cross-project-file-disclosure
CVE-2026-105699: файлы MCP в Langflow
Langflow аутентифицировал подключение MCP, но не проверял права на каждый запрошенный файл. Пользователь мог читать файлы чужих потоков; проверка владельца исправлена в версии 1.9.1.[1], [2], [5]
Вектор CVSS
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:NПредставьте отель, который проверяет ваш ключ, а затем выдаёт багаж из любого номера, если назвать бирку. Ключ доказывает право войти в отель, но не то, что чемодан другого гостя принадлежит вам. Перед открытием файла чтение MCP в Langflow должно проверить владельца и проект.[1]
Ключевые понятия и термины
Model Context Protocol (MCP)- Протокол, с помощью которого приложение ИИ запрашивает инструменты и ресурсы у сервера. Сервер по-прежнему должен проверять права на каждый объект.[1]
MCP-конечная точка проекта- Подключение Langflow MCP, связанное с проектом. Доступ к этой конечной точке не открывает файлы всех проектов.[1]
resources/read- Операция MCP, запрашивающая у сервера ресурс, указанный URI.[1]
Связи со стандартами
- Ссылка CWE для слабого места, описанного в этом руководстве: CWE-639
Анализ первопричины
В затронутых версиях Langflow с 1.6.8 по 1.9.0 транспорт MCP, привязанный к проекту, аутентифицировал доступ к ID проекта из URL подключения. Затем обработчик resources/read принимал URI ресурса, извлекал ID потока и имя файла и передавал их в storage_service.get_file(), не проверяя, принадлежит ли поток аутентифицированному пользователю или текущему проекту. Хранилище читает по пространству имён и имени файла; оно не знает разрешений Langflow для пользователей и проектов. Поэтому пользователь с учётной записью и доступом к MCP-конечной точке своего проекта мог запросить файл из пространства имён потока другого пользователя. Отдельно описанное глобальное поведение resources/list и tools/list могло раскрыть идентификаторы и упростить выбор цели, но для чтения оно не требовалось. Это аутентифицированное нарушение конфиденциальности между пользователями, а не анонимный доступ или выполнение кода. В записи CVE указаны CVSS 4.0 7.1 High и CWE-639. Langflow 1.9.1 исправляет путь: handle_read_resource() получает аутентифицированного пользователя и находит поток с условиями Flow.user_id == current_user.id, а для транспорта проекта также Flow.folder_id == project_id; неразрешённое пространство имён отклоняется до обращения к хранилищу. Патч также запрещает разделители и последовательности traversal, проверяет границы путей при чтении/записи/удалении и ограничивает глобальные списки текущим пользователем. Регрессионный тест сопровождающего запрещает чтение потока другого пользователя.[1], [2], [3], [5]
Пошаговый сценарий атаки
Пользователь входит в собственную MCP-точку проекта
Злоумышленнику нужна учётная запись Langflow и доступ хотя бы к одному подключению MCP проекта. Уязвимость не обходит вход в систему.[1]
Клиент запрашивает URI ресурса
Запрос MCP resources/read содержит URI, последние компоненты которого задают пространство имён потока и имя файла.[1]
Хранилище читает по пространству имён
storage_service.get_file() возвращал файл из указанного пространства. У хранилища не было контекста владельца-пользователя.[1]
Исходный код: Уязвимый vs Защищённый вариант
Это целевые фрагменты Python из описанного пути, а не отдельное приложение. Уязвимый путь считал переданное клиентом пространство имён достаточным подтверждением полномочий. Исправление 1.9.1 сначала находит поток в области аутентифицированного пользователя и, для MCP-подключения проекта, текущего проекта; лишь после этого хранилище может его прочитать. Патч также проверяет имена файлов и ограничивает пути на уровне хранилища, чтобы другие операции чтения, записи и удаления не обходили проверку. Проверяйте права в службе, которой известны пользователь и проект: адаптер хранилища не может вывести владельца самостоятельно. Границы фрагмента: реальный обработчик также разрешает файл из пользовательского хранилища только тогда, когда пространство имён совпадает с ID текущего пользователя и сервер не ограничен проектом. Этот отдельный путь не показан; фрагмент нельзя трактовать как разрешение доступа к произвольным пространствам имён. В upstream-наборе регрессионных тестов есть test_handle_read_resource_denies_other_users_flow, проверяющий отказ в межпользовательском чтении.[1], [3], [4], [7]
Фрагмент исходного кода: mcp_utils.py — целевые фрагменты исходного кода
# Фрагмент затронутого пути чтения: разобранные ID напрямую передавались в хранилище.
content = await storage_service.get_file(
flow_id=flow_id,
file_name=filename,
)
# Сокращённое представление границы авторизации версии 1.9.1 в стиле исходного кода.
current_user = current_user_ctx.get()
query = select(Flow).where(
Flow.id == namespace_id,
Flow.user_id == current_user.id,
)
if project_id is not None:
query = query.where(Flow.folder_id == project_id)
flow = (await session.exec(query)).first()
if flow is None:
raise ValueError("Resource not found or access denied")
content = await storage_service.get_file(
flow_id=namespace_id,
file_name=filename,
)
Чек-лист по защите системы для инженеров
- ✓Обновите Langflow до версии 1.9.1 или новее и проверьте фактически развёрнутый пакет и образ контейнера, а не только исходный код.[5]
- ✓Перед вызовом хранилища проверяйте каждую URI
resources/readпо аутентифицированному пользователю и проекту подключения MCP.[1], [3] - ✓Преобразуйте идентификатор в объект базы данных и требуйте принадлежность пользователю, а для конечных точек проекта — и текущему проекту.[1], [3]
- ✓Предпочитайте непрозрачные ID ресурсов, созданные сервером, произвольным путям хранилища или URI загрузки от клиента.[1], [3]
- ✓Проверяйте имена после декодирования, отклоняйте разделители и компоненты traversal и ограничивайте канонический путь на уровне хранилища для чтения, записи и удаления.[1], [3]
- ✓Ограничьте запросы
resources/listиtools/listаутентифицированным пользователем; перечисление ID — отдельная утечка, усиливающая дефект авторизации.[7] - ✓Добавьте регрессионный тест с двумя пользователями: MCP-конечная точка проекта одного должна отклонять файлы потоков другого и потоки чужих проектов.[1]
- ✓Проверьте журналы затронутых установок и оцените возможное раскрытие; уведомление описывает дефект, а не подтверждённую эксплуатацию в реальной среде.[7], [3]
- ✓Сохраните upstream-регрессионный тест
test_handle_read_resource_denies_other_users_flowи добавьте проверку области проекта, подтверждающую отказ для собственного потока пользователя вне текущего проекта.[7], [3]
Источники
- Langflow maintainer advisory GHSA-4hmc-cfm3-w43c
- CVE Program record CVE-2026-105699
- Upstream fix commit b8fe970
- Upstream pull request #12818 and regression coverage
- Langflow 1.9.1 release
- MITRE CWE-639 — Authorization Bypass Through User-Controlled Key
- Langflow regression tests — MCP resource authorization