CVE-2026-111497
Broccoli2Shell: RCE в Brotli — CVE-2026-111497
Ошибка декодера Brotli угрожает Node.js и Python при распаковке недоверенных данных. Разбор Broccoli2Shell: затронутые версии, проверка окружения и порядок обновления.
Кому нужно проверить
Разработчикам и владельцам Node.js- и Python-сервисов, командам эксплуатации контейнеров, SSR-приложений, краулеров, интеграций, обработки файлов и импорта по URL. Проверьте также фоновые workers, планировщики, CI и приложения со встроенной C-библиотекой Brotli. Важна не только марка продукта, но и конкретная версия, способ установки, операционная система и конфигурация.
В чём риск
Broccoli2Shell, Broccoli и Node2Shell — неформальные названия CVE-2026-111497. Первопричина находится в c/dec/decode.c библиотеки Google Brotli. Недопустимое переключение блока ошибочно воспринималось как временная нехватка входных данных, а не окончательная ошибка формата. Потоковый декодер продолжал добавлять байты во внутренний восьмибайтовый буфер и мог записывать за его границы, повреждая соседнее состояние. Google связывает дефект с CWE-252 и CWE-787. Возможны падение процесса, раскрытие памяти и выполнение кода с полномочиями приложения. Это не обычная «архивная бомба»: ограничение объёма распаковки само по себе не исправляет нарушение безопасности памяти. Уязвим именно путь декодирования. Выдача собственных статических файлов с Brotli-сжатием не доказывает наличие входного пути атаки. В то же время сервису не обязательно принимать загрузки: HTTP-клиент может автоматически распаковать ответ внешнего сервера с Content-Encoding: br. TLS подтверждает защищённое соединение с этим сервером, но не безопасность полученных сжатых данных. Наличие уязвимой версии не доказывает уже состоявшуюся компрометацию; отсутствие падений также не доказывает безопасность.
Затронутые версии
Google указывает три диапазона C-библиотеки: 1.0.3 ≤ версия < 1.0.10; 1.1.0 ≤ версия < 1.1.1; 1.2.0 ≤ версия < 1.2.1. Исправленные backport-релизы 1.0.10 и 1.1.1 нельзя включать в общий диапазон «всё до 1.2.1». В поддерживаемых ветках Node.js затронуты 22.x до 22.23.4, 24.x до 24.22.1 и 26.x до 26.12.1. Для EOL-веток переходите на поддерживаемую сборку или требуйте подтверждение исправления от поставщика. Для PyPI GitHub Advisory указывает Brotli ≥ 1.0.3 и < 1.2.1, brotlicffi ≥ 1.0.3 и < 1.2.1.0. При этом PYSEC-2026-4322 и PYSEC-2026-4323 задают более широкий диапазон от начала истории пакетов до исправленных релизов. Нижняя граница в источниках расходится: не считайте старый Python-пакет безопасным только потому, что он ниже 1.0.3; инвентаризируйте все установки до 1.2.1 / 1.2.1.0. Для остальных продуктов определяйте наличие именно уязвимого C-декодера и достижимость распаковки; одного слова Brotli в списке функций недостаточно.
Исправленные версии
Минимальные исправления: Google Brotli 1.0.10, 1.1.1 или 1.2.1 в соответствующей ветке; Node.js 22.23.4, 24.22.1 или 26.12.1; PyPI Brotli 1.2.1 и brotlicffi 1.2.1.0. Выбирайте актуальный поддерживаемый релиз с этим исправлением. Обновите сам runtime Node.js, а не только npm-зависимости: стандартная сборка содержит собственный Brotli. Обновление системной libbrotli не заменяет обновление встроенной копии. В Python проверьте каждый virtualenv и wheel, в контейнерах — каждый финальный образ. Пересоберите приложения со статически встроенной библиотекой, обновите lock-файлы и базовые образы, разверните новые артефакты и перезапустите все процессы. Для пакетов ОС сверяйте security advisory поставщика: backport может сохранять старый upstream-номер.
Что сделать
- 1Составьте карту установок. Запишите владельца сервиса, фактический исполняемый файл, версию runtime, окружение Python, версию пакета и идентификатор образа. Проверьте production, staging, фоновые задачи, CI и резервные экземпляры. Версия node или python в интерактивной оболочке администратора может отличаться от версии процесса приложения. Для managed-хостинга запросите подтверждение обновления runtime именно вашего приложения.
- 2Проверьте исходящие HTTP-запросы. Встроенный fetch в Node.js и Python-клиенты с поддержкой Brotli могут декодировать ответы автоматически. PyPA отдельно перечисляет urllib3/requests, aiohttp и httpx с brotli extra. Найдите импорт по URL, предпросмотр ссылок, краулеры, получение документов, обращения к внешним API и обработку ответов webhook-интеграций. Атакующий должен контролировать данные, которые действительно попадают в декодер; открытый входящий порт для этого сценария не обязателен.
- 3Проверьте входящие тела и прямые вызовы. Выясните, распаковывают ли middleware или парсеры Content-Encoding: br до валидации JSON, проверки подписи или бизнес-логики. Сам по себе низкоуровневый node:http не означает автоматической распаковки. Найдите brotliDecompress, createBrotliDecompress, brotli.decompress и соответствующие обёртки; проверьте загрузки, сообщения очередей, кэши и файлы из недоверенных источников. Express и body-parser могут быть путём к декодеру, но исправление C-библиотеки требует обновления runtime.
- 4Обновите Node.js в каждой используемой ветке минимум до 22.23.4, 24.22.1 или 26.12.1. Для ветки вне поддержки запланируйте переход на поддерживаемую. Проверьте Dockerfile, конфигурацию платформы, CI и менеджер процессов: обновление локального Node.js разработчика не меняет production. Зафиксируйте выбранный исправленный артефакт и проверьте версию внутри финального запущенного контейнера, а не только в стадии сборки.
- 5В Python обновите используемый пакет Brotli минимум до 1.2.1, brotlicffi — до 1.2.1.0; если установлены оба, проверьте оба. Согласуйте зависимости и lock-файлы через принятый в проекте менеджер пакетов. Не устанавливайте второй пакет только ради этой проверки. Обновление самого интерпретатора Python не гарантирует замену wheel в virtualenv. Если пакет поставляет ОС, используйте её исправленный пакет и advisory вместо произвольной установки pip поверх системного окружения.
- 6Проверьте встроенные копии. SBOM и системный менеджер пакетов могут не показать статически включённый Brotli, копию в бинарном расширении или отдельный runtime внутри приложения. Для сторонних продуктов запросите подтверждение поставщика. Для собственных сборок обновите исходную зависимость и пересоберите конечные бинарные файлы. Не переносите выводы автоматически на независимые реализации алгоритма: CVE описывает конкретный C-декодер Google.
- 7Если обновление задерживается, временно перекройте достижимые пути распаковки. Для входящих запросов отклоняйте Brotli-кодирование до попадания в уязвимый парсер, учитывая прямой доступ к backend и влияние на клиентов. Для Python можно рассмотреть удаление необязательной Brotli-поддержки и extras после тестирования зависимостей. Проверьте, что альтернативный пакет не включает декодирование снова. Удаление br из Accept-Encoding недостаточно: недоверенный сервер способен прислать такой ответ независимо от согласования. Входящий WAF не закрывает распаковку исходящих HTTP-ответов. Эти меры частичные и не заменяют исправление.
- 8Проверьте совместимость на staging. Прогоните штатные запросы и загрузки, получение обычных Brotli-ответов, обработку ошибок, очереди и критичные интеграции. В changelog brotlicffi 1.2.1.0 отдельно указано более строгое отклонение лишних байтов после завершённого потока; приложения, которые полагались на прежнее поведение, могут получить ошибку. Не проверяйте production скачанным эксплойтом. Для подтверждения исправления используйте происхождение сборки, версии и сведения поставщика; штатная успешная распаковка сама по себе не доказывает отсутствие CVE.
- 9Пересоберите образы на обновлённой базе, разверните их и перезапустите все workers и реплики. Уже работающий процесс продолжает использовать загруженный код до перезапуска. Проверьте фактические версии после выкладки, фоновые задачи и автоскейлинг: старый шаблон или lock-файл способен вернуть уязвимый компонент. Подготовьте восстановление на исправленную сборку и контролируйте ошибки распаковки, перезапуски, доступность и расход ресурсов.
- 10При расследовании сопоставьте падения и ошибки декодирования с запросами, внешними ответами и временем обработки задач. Неожиданные дочерние процессы, изменения файлов или сетевые соединения требуют отдельного анализа; ни один из этих признаков не является уникальным индикатором Broccoli2Shell. Сохраните журналы и метаданные образов, ограничьте доступ подозрительного узла и следуйте процедуре реагирования. При подтверждённой компрометации замените доступные процессу секреты и восстановите систему из доверенного образа: обновление библиотеки не удаляет уже внедрённый код.
- 11Учитывайте даты и границы доказательств. Исправляющий upstream-коммит 0ed4268 датирован 27 февраля 2026 года; наличие изменения в исходниках не означает, что старые бинарные релизы уже исправлены. Security-релизы Google Brotli и Node.js вышли 21 октября, CVE опубликован 22 октября, Python-advisories PyPA — 23 октября. В записи CISA ADP с отметкой времени 23 октября поле Exploitation имеет значение none; это датированная оценка, а не гарантия отсутствия атак на 26 октября. Не смешивайте демонстрацию исследователей, публичный PoC и подтверждённые атаки в реальной инфраструктуре.
Как недоверенные данные доходят до декодера
Два входных пути сходятся на одном компоненте: тело запроса к приложению или ответ сервера, к которому приложение обратилось само. Порядок ниже объясняет механизм и точку исправления без вредоносного потока.
- 1Источник: внешний HTTP-ответ, входящее тело, файл или сообщение содержит Brotli-данные.
- 2HTTP-клиент, middleware или код приложения передаёт данные C-декодеру Brotli.
- 3Уязвимый декодер принимает недопустимое переключение блока за нехватку входных данных.
- 4Продолжение обработки может вызвать запись за границы буфера и повреждение памяти процесса.
- 5Исправленная библиотека различает нехватку данных и ошибку формата, прекращая неверную обработку.
- 6Обновление достигает production только после пересборки нужных артефактов, выкладки и перезапуска.
Примеры конфигурации и проверки
node -p 'JSON.stringify({
node: process.version,
brotli: process.versions.brotli,
executable: process.execPath
}, null, 2)'Команда только выводит версии и путь к исполняемому файлу. Запускайте её в окружении приложения или внутри нужного контейнера. Сравните версию Node.js с исправлением своей ветки и advisory поставщика. Для backport-сборки один номер встроенной библиотеки может быть недостаточен. Команда не обращается к сети, не распаковывает данные и не проверяет работающие процессы автоматически.
python - <<'PY'
import sys
from importlib.metadata import PackageNotFoundError, version
print('Python:', sys.version.split()[0])
print('Executable:', sys.executable)
for package in ('Brotli', 'brotlicffi'):
try:
print(package + ':', version(package))
except PackageNotFoundError:
print(package + ': not installed in this environment')
PYДля Python 3.8+; используйте интерпретатор конкретного virtualenv. Читаются метаданные установленных дистрибутивов, нативный декодер не импортируется. Ожидаемые исправленные минимумы — Brotli 1.2.1 и brotlicffi 1.2.1.0. Сообщение об отсутствии пакета относится только к этому окружению и не исключает встроенную копию, другой virtualenv или runtime в контейнере.
python -m pip show Brotli brotlicffi
python -m pip checkВ окружении с pip первая команда показывает установленные пакеты, их расположение и зависимости; отсутствующий пакет может вызвать предупреждение. Вторая проверяет совместимость объявленных требований. Обе команды диагностические. Результат No broken requirements found означает согласованность зависимостей, а не отсутствие CVE. После обновления повторите проверку версий и подтвердите перезапуск приложения.
Как не подпустить ботов к сайту
BotProtection принимает запросы перед вашим сайтом и фильтрует автоматизированные обращения. Поэтому ботам сложнее добраться до уязвимого компонента и начать его проверять или атаковать, а вероятность успешной автоматизированной атаки становится значительно ниже. Это дополнительный слой защиты: обновление уязвимых компонентов, проверка журналов и реагирование на инциденты остаются обязательными.
Первоисточники
- Google CNA: запись CVE и точные диапазоны
- Node.js: security-релизы 21 октября 2026
- Google Brotli: исправленные релизы
- Google Brotli: исправление обработки потока
- GitHub Advisory: Python Brotli и brotlicffi
- PyPA: PYSEC-2026-4322 для Brotli
- PyPA: PYSEC-2026-4323 для brotlicffi
- PyPI: Brotli 1.2.1
- PyPI: brotlicffi 1.2.1.0 и changelog
- Broccoli2Shell: независимый обзор и название
Снизьте шанс атаки до того, как бот дойдёт до сайта
Подключите BotProtection как фильтр перед сайтом: подозрительные автоматизированные запросы отсекаются до обращения к вашему серверу. Это значительно снижает вероятность автоматизированной атаки, но не исправляет саму уязвимость, поэтому обновление и настройка компонентов остаются обязательными.