Уязвимость в декодере Brotli (CVE-2026-111497) задела Node.js, Python и HTTP-софт

Компания Aikido опубликовала разбор уязвимости CVE-2026-111497 в декодере Brotli. Brotli, алгоритм сжатия без потерь и формат данных от Google; он широко применяется для HTTP-сжатия веб-контента (HTML, CSS, JavaScript). Уязвимость, запись за пределы буфера (out-of-bounds write) в декодере Google Brotli версий с 1.0.3 по 1.2.0 на всех платформах. Оценка по CVSS v4.0, 9.2 (критическая).
Согласно Aikido, удалённый неаутентифицированный атакующий может отправить специально собранный поток Brotli и тем самым повредить память, добиться утечки данных, обрушить процесс или потенциально выполнить произвольный код. Механизм таков: ошибка заставляет декодер продолжать принимать байты там, где данные нужно отклонить; лишние байты переполняют небольшой рабочий буфер и портят память. Через эту порчу можно управлять тем, что исполняется.
Хронология по тексту Aikido: Node.js раскрыл уязвимость под названием «node2shell» (в тексте дата указана и как среда, 21 октября, и как среда, 22 октября). Процесс Node.js, который распаковывает подконтрольные атакующему данные Brotli, можно заставить утечь память или выполнить произвольный код; под угрозой были приложения и библиотеки, распаковывающие испорченный Brotli (например, встроенный fetch() и body-parser). Затем Python выпустил обновление безопасности для того же дефекта: пакеты Python тоже уязвимы. В пятницу, 23 октября, стало известно, что проблема затрагивает и другие крупные языки и серверные приложения на HTTP, где исправления ещё доступны не полностью. В разделе с патчами уязвимость названа HTTP2Shell.
OpenAI сообщила, что обнаружила уязвимость в феврале и описала её как неаутентифицированное удалённое выполнение кода, работающее в обе стороны: вредоносный клиент может захватить непропатченный сервер, а вредоносный сервер, непропатченный клиент, принимающий сжатые ответы. Первопричину в исходном коде Brotli исправили ещё в феврале, но тогда не поняли, что она создаёт уязвимость безопасности, и релиза с исправлением не выходило до сих пор. Поэтому каждому проекту, который включает Brotli в себя, нужно выпускать собственное обновление.
Техническая суть: дефект в функции DecodeBlockTypeAndLength(), отвечающей за переключение блоков (моменты, когда поток меняет используемое дерево Хаффмана). В уязвимых версиях она возвращает обычное булево значение, и BROTLI_FALSE может означать и «поток повреждён», и «нужно больше данных»; вызывающий код их не различает, а на быстром пути декодер вообще отбрасывает возвращаемое значение. Специально собранный поток объявляет один тип блока и исчерпывает его длину, что вынуждает невозможное переключение. Декодер либо сообщает, что ему нужно больше данных для полного потока, либо продолжает декодирование со старым состоянием блока, второй путь и приводит к записи за границы буфера. Исправление (коммит google/brotli 0ed4268) заставляет функцию возвращать код ошибки и добавляет новую ошибку BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH (-17); декодирование теперь останавливается при ошибке формата и на безопасном, и на быстром пути. По данным OSM, пересказанным Aikido, версия 1.2.1 отличается от 1.2.0 только повышением номера версии и изменениями декодера из этого коммита.
В Python уязвимы два пакета PyPI, Brotli и brotlicffi, собирающие тот же декодер, что встроен в Node.js. У пакета Brotli 82,8 млн загрузок в месяц. Клиенты вроде requests, httpx и aiohttp подгружают эти пакеты автоматически, если они установлены, так что приложение может быть уязвимо, даже не импортируя Brotli в собственном коде. Данные атакующего могут дойти до декодера двумя путями: через исходящие запросы (сервер атакующего отдаёт ответ Brotli, например, при доставке вебхука, предпросмотре ссылки, работе краулера или функции «загрузить по URL») и через входящие (фреймворк или промежуточный слой декодирует тело запроса с Content-Encoding: br).
В обновлении от 4:12 PM PT Aikido сообщила, что исправления есть для libbrotli, Python, C++, NodeJS, bun и Envoy, ожидаются и другие; Apache и Nginx по умолчанию Brotli не декодируют.
Ключевые факты
- CVE-2026-111497, запись за пределы буфера в декодере Google Brotli версий 1.0.3-1.2.0; оценка CVSS v4.0, 9.2 (критическая). Удалённый атакующий без аутентификации может повредить память, добиться утечки данных, обрушить процесс или потенциально выполнить код.
- Сначала проблему раскрыл Node.js (Node2Shell), затем выяснилось, что уязвимы и пакеты Python Brotli и brotlicffi (у Brotli 82,8 млн загрузок в месяц) и другое ПО с HTTP; в разделе с патчами уязвимость названа HTTP2Shell.
- OpenAI заявила, что нашла уязвимость в феврале; первопричину тогда поправили в исходниках Brotli, но не распознали как проблему безопасности, и релиз с исправлением не выходил до сих пор.
- Исправленные версии: Node.js 22.23.4, 24.22.1 или 26.12.1; libbrotli 1.2.1 (для старых веток 1.0.10 или 1.1.1); Python Brotli 1.2.1, brotlicffi 1.2.1.0; Bun 1.4.4; Envoy 1.40.0, 1.39.3, 1.38.6 или 1.37.8.
- Если обновиться нельзя, Aikido советует отключить декодирование Brotli; изменения только заголовка Accept-Encoding недостаточно, так как вредоносный сервер может прислать Brotli в любом случае.
Почему это важно
Brotli используется для HTTP-сжатия веб-контента, поэтому дефект в его декодере затрагивает не один продукт, а целую цепочку: встроенную библиотеку Node.js, пакеты Python, а также другие HTTP-серверы, прокси, шлюзы и клиенты. Уязвимость критическая (CVSS v4.0, 9.2) и эксплуатируется удалённо без аутентификации, причём в обе стороны: под ударом и серверы, принимающие сжатые запросы, и клиенты, принимающие сжатые ответы. Усугубляет ситуацию то, что исправление в исходниках Brotli появилось ещё в феврале, но релиза с ним не было, так что каждому проекту, включающему Brotli, нужно выпускать своё обновление.
Кому это важно
Разработчикам и администраторам, у которых в любом окружении установлены Brotli 1.2.0 и старше или brotlicffi 1.2.0.x: ноутбуки, CI-раннеры, серверы, контейнеры. Особенно тем, чьи сервисы ходят на внешние серверы (вебхуки, предпросмотр ссылок, краулеры, функции «загрузить по URL») или принимают тела запросов со сжатием br. Также пользователям Node.js, Bun, Envoy, Istio, curl/libcurl и систем, которые подтягивают Brotli косвенно, например через Scrapy или HTTP-клиенты requests, httpx и aiohttp.
Как это применить
Проверьте, декодирует ли ваш код или его зависимости Brotli, и обновитесь: Node.js, до 22.23.4, 24.22.1 или 26.12.1 (либо новее в своей ветке); нативный Brotli, до 1.2.1 (старые ветки, 1.0.10 или 1.1.1); Python-пакеты, Brotli до 1.2.1 и brotlicffi до 1.2.1.0; Bun, до 1.4.4 с пересборкой исполняемых файлов, которые его включают; Envoy, до 1.40.0, 1.39.3, 1.38.6 или 1.37.8; в Istio исправление есть в 1.29.9, 1.30.6 и 1.31.2. Для curl/libcurl обновляйте зависимость Brotli или пакет вендора, для пакетов операционной системы ставьте обновление безопасности (вендоры могут перенести исправление без смены номера версии). В Python: pip install -U "Brotli>=1.2.1" или "brotlicffi>=1.2.1.0", обновите lock-файл, пересоберите образы контейнеров и колёса, проверьте все окружения. Если обновиться пока нельзя: в Python можно удалить Brotli и brotlicffi (убрав также extras вроде httpx[brotli]); на входе, отклонять запросы с br в Content-Encoding на обратном прокси, балансировщике или в промежуточном слое; на выходе, убрать br из Accept-Encoding и отключить декодирование Brotli либо отклонять такие ответы до начала декодирования.
Можно ли доверять
Источник, блог компании Aikido, которая занимается безопасностью и в конце текста рассказывает, как её продукт помогает находить уязвимые версии, то есть у публикации есть и рекламная часть. Технические данные (версии, номер коммита, оценка 9.2) приведены подробно, но в самом тексте есть расхождения: дата раскрытия в Node.js указана как 21 октября в кратком изложении и как 22 октября в хронологии. Рассказ OpenAI о находке в феврале передан в пересказе Aikido; ссылка на сами рекомендации OpenAI в тексте лишь упомянута. Доступный текст оборван на середине описания исправления для Python, поэтому конец статьи не учтён.
Риски и подводные камни
Базы уязвимостей на 23 октября не сопоставляют CVE с пакетами PyPI, поэтому pip-audit, Dependabot и Safety пока не пометят уязвимые версии. Примечания к выпускам исправленных пакетов Python CVE не упоминают. Образ контейнера, собранный на уязвимой версии, остаётся уязвимым до пересборки; Brotli может быть вшит или статически скомпонован в приложения, тогда нужна новая сборка самого приложения. Удаление пакетов в Python не убирает отдельные декодеры Brotli, встроенные в другие среды выполнения и продукты, а если сервер всё равно пришлёт Brotli, ответ может оказаться нечитаемым или вызвать ошибку: автоматический откат не гарантирован. Одной правки Accept-Encoding мало, поскольку вредоносный сервер может прислать Brotli независимо от заявленного клиентом, а проверку нужно делать до автоматической обработки тела ответа. Для части продуктов (в тексте упомянуты «другие, ожидаются») исправлений пока нет.