FlawOpen

flawopen.com/Teardowns/cve-2026-5027-langflow-multipart-file-write

● CVE-2026-5027 · CVSS 8.8[1], [2] · Высокий
Исследования · FlawOpen

Langflow CVE-2026-5027: обход пути при загрузке файла

CVE-2026-5027 позволяла записывать файлы вне каталога загрузки Langflow. GTIG сообщает об эксплуатации; обновитесь до 1.9.0+.[1], [2], [6]

Вектор CVSSCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H[1], [2]
💡 Простыми словами (ELI5)

Почтовое отделение принимает посылку, адрес и ярлык которой выбирает отправитель. Если сотрудник приклеит ярлык к папке отделения, не проверив конечный путь, посылка может оказаться за его пределами. Маршрут загрузки Langflow доверял multipart-имени файла, а слой хранения отдельно не проверял, что итоговый путь остается внутри разрешенной папки.[2], [3]

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

CVE-2026-5027
Идентификатор Tenable для обхода пути через multipart-имя в POST /api/v2/files Langflow: CWE-22, CVSS 3.1 8,8; нужны низкие привилегии.[1], [2]
Multipart-имя файла
Имя, переданное клиентом в заголовке Content-Disposition multipart-запроса. Это недоверенные данные, а не безопасный файловый путь.[1], [2]
Ограничение пути
Проверка, которая канонически разрешает целевой путь и подтверждает, что он остается внутри разрешенного каталога хранения до создания или записи файла.[3], [4], [7]
Примечание об идентификаторах
В связанном GHSA Langflow указан CVE-2026-33309, а Tenable и Google GTIG используют CVE-2026-5027. В статье используется идентификатор GTIG; оба источника сохранены без незаметного объединения их метаданных.[4], [5], [6]

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

  • Ссылка CWE для слабого места, описанного в этом руководстве: CWE-22

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

Запись Tenable для CVE-2026-5027 сообщает, что POST /api/v2/files принимал multipart-имя с компонентами обхода пути и записывал файл вне целевого каталога. Граница безопасности проходит через API-маршрут и локальное хранилище: проверка параметров URL не проверяет имя из multipart Content-Disposition, а добавление имени к каталогу не доказывает, что путь остается внутри него. Вектор CVE требует низких привилегий (PR:L); не утверждайте, что сама CVE обходит аутентификацию. Google GTIG включает CVE-2026-5027 в список подтвержденных случаев эксплуатации в реальных атаках, но публичное резюме не доказывает универсальное выполнение кода. Последствия произвольной записи зависят от доступных для записи путей, прав процесса и конфигурации; это условный риск, а не гарантированный RCE. В связанном GHSA Langflow указан CVE-2026-33309 и также указано исправление в 1.9.0. Здесь используется CVE-2026-5027 по данным Tenable и GTIG; расхождение идентификаторов отмечено явно. Влитый патч Langflow проверяет имена на уровне API и каноническое ограничение пути в хранилище, в том числе до создания каталогов.[1], [2], [3], [4], [5], [6]

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

Шаг 1

Пользователь с низкими привилегиями обращается к загрузке

Вектор CVSS для CVE-2026-5027 требует низких привилегий. Затронут POST /api/v2/files; запись не подтверждает обход аутентификации.[1], [2]

Шаг 2

Запрос передает multipart-имя

Имя берется из контролируемых клиентом метаданных Content-Disposition. Проверка URL-параметров не очищает этот отдельный источник данных.[1], [2], [4]

Шаг 3

Путь пересекает границу хранилища

Без проверки канонического ограничения компоненты обхода могут разрешиться за пределами каталога загрузки.[1], [2], [3], [7]

Шаг 4

Файл записывается за пределами корня

Документированное последствие — произвольная запись файла. Выполнение кода зависит от доступных путей, прав процесса и развертывания; не всякая загрузка приводит к RCE.[1], [2], [6]

Шаг 5

Исправьте обе границы проверки

Langflow объединил проверку имен в API и каноническое ограничение в хранилище в ветке 1.9.0. Обновите пакеты и проверьте работающий образ.[2], [3], [4]

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

Это сокращенные примеры, повторяющие форму исходного кода, а не дословный diff upstream. Уязвимый путь считает имя клиента путем хранения. Защищенный шаблон проверяет имя и каноническое положение назначения относительно корня на уровне хранения; PR upstream также запрещает разделители и управляющие символы и проверяет границу до создания каталогов. Проверка в хранилище нужна даже при валидации HTTP-слоем. Пример требует версию Python с Path.is_relative_to и сам по себе не устраняет гонки проверки и использования в доступных злоумышленнику каталогах. В production используйте устойчивые к гонкам файловые операции и строгие права. Защита здесь — ограничение пути, а не только черный список имен.[3], [2], [4], [7]

Фрагмент исходного кода: Langflow api/v2/files.py и services/storage/local.py — сокращенный пример границы безопасности

УЯЗВИМАЯ РЕАЛИЗАЦИЯ
# Упрощенный пример уязвимого потока данных.
new_filename = file.filename
file_path = folder_path / new_filename
await write_upload(file, file_path)
БЕЗОПАСНЫЙ ИСПРАВЛЕННЫЙ ВАРИАНТ
from pathlib import Path

def confined_upload_path(root: Path, client_name: str | None) -> Path:
    name = Path(client_name or "").name
    if not name or name in {".", ".."} or chr(0) in name:
        raise ValueError("invalid upload filename")

    base = root.resolve()
    target = (base / name).resolve()
    if not target.is_relative_to(base):
        raise ValueError("upload path escapes storage root")
    return target

# Вызывайте на границе хранилища непосредственно перед созданием или записью.
target = confined_upload_path(upload_root, file.filename)
await write_upload(file, target)

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

Источники