# Модель угроз — CVE-2026-111497 (запись за границы буфера в декодере Brotli)

Документ определяет, что инструмент считает подверженным воздействию, что он явно не покрывает
и почему классификация проведена именно так. Это опорный документ для толкования любого вердикта,
который возвращают скрипты.

## 1. Уязвимость

| Свойство | Значение |
|---|---|
| Идентификатор | CVE-2026-111497 |
| Компонент | Google Brotli, декодер (`c/dec/decode.c`) |
| Слабость | CWE-787, запись за границы буфера |
| Уязвимые выпуски upstream | 1.0.3 … 1.0.9, 1.1.0, 1.2.0 |
| Исправленные выпуски upstream | 1.0.10, 1.1.1, 1.2.1 (21 октября 2026) |
| Вектор атаки | специально сформированный поток Brotli, переданный декодеру |
| Требуется аутентификация | нет |
| Воздействие | падение процесса, повреждение памяти, в некоторых конфигурациях удалённое выполнение кода |
| Критичность | CVSS 4.0 9.2 по публикации проекта; 8.5 по шкале CVSS 3.x в трекерах дистрибутивов |

Дефектный путь — конечный автомат декодера на переходе между блоками: некорректный поток
проводит внутренние счётчики за предполагаемую границу, и декодер пишет за пределы выделенного
выходного буфера вместо того, чтобы своевременно сообщить о недопустимом потоке. Исправление
upstream обнаруживает и отклоняет такой поток до записи.

## 2. Что находится под воздействием, а что нет

Различие, от которого зависит большинство вердиктов:

- **Кодировщик** (nginx `ngx_brotli`, `mod_brotli`, конвейеры сборки статики) сжимает данные,
  которые произвёл сам сервер. Он никогда не разбирает Brotli, контролируемый нарушителем.
  Это не поверхность атаки, хотя он и связан с тем же пакетом.
- **Декодер** принимает данные извне и разбирает их. Это и есть поверхность атаки.

| Путь | Подвержен, когда | Примечания |
|---|---|---|
| Тело HTTP-запроса | приложение или прокси распаковывает `Content-Encoding: br` | вектор с наибольшим воздействием там, где он существует |
| Исходящий HTTP-клиент | libcurl с пустым `CURLOPT_ENCODING`, Node `fetch`, Python `httpx`/`requests` с Brotli | злонамеренная или скомпрометированная третья сторона отвечает `br` |
| Цепочка ответов через прокси | включён декомпрессор HTTP в Envoy/Istio | прокси становится декодером |
| Загрузка или импорт файла | приложение распаковывает архивы или потоки Brotli | часто упускается при аудите |
| Встроенная среда выполнения | декомпрессия запросов в Node.js, Bun, .NET | исправление приходит со средой выполнения, а не с `libbrotli1` |

## 3. Почему libcurl доминирует в реальных парках

Замерено на трёх боевых хостах: достижимым вектором ни разу не оказались «запросы к веб-серверу»,
поскольку nginx и Apache использовали Brotli только для сжатия и ни один из них не декодировал
тела запросов. Доминирующим путём был **исходящий HTTP через libcurl**, вызываемый из кода
PHP-приложений.

`CURLOPT_ENCODING`, установленный в пустую строку, указывает libcurl объявлять и принимать все
кодировки, которые он поддерживает, включая `br`. Этот единственный аргумент встречается в:

- WordPress `wp-includes/Requests/src/Transport/Curl.php`;
- WordPress SimplePie `File.php`;
- фабриках обработчиков Guzzle, поставляемых внутри плагинов;
- прямом трафике `wp_remote_*`, загрузке RSS и вызовах API сторонних поставщиков.

На одном хосте инвентаризация насчитала 164 PHP-файла с `CURLOPT_ENCODING` или
`CURLOPT_ACCEPT_ENCODING`. Именно это число, а не сам факт наличия пакета, служит реальной мерой
подверженности на хосте общего хостинга.

## 4. Модель нарушителя

| Позиция нарушителя | Возможность | Последствие |
|---|---|---|
| Удалённая, без аутентификации | отправляет специально сформированное тело Brotli или отдаёт такой ответ `br` | падение, повреждение памяти, возможное выполнение кода в процессе декодирования |
| Поставщик стороннего контента | контролирует конечную точку, к которой обращается сервер | достигает пути декодирования libcurl, не касаясь периметра |
| Локальная без привилегий | передаёт файл, который распаковывает приложение | тот же декодер, меньшее воздействие |

Инструмент исходит из того, что нарушитель может выбирать байты, но не может выбирать процесс:
цель аудита — убедиться, что ни в одном процессе не осталось достижимого декодера.

## 5. Стратегия обнаружения

Наличие пакета не означает подверженности. Поэтому детектор фиксирует четыре независимых факта
и классифицирует только после того, как известны все четыре:

1. установленная версия, из которой удалены epoch и ревизия дистрибутива до номера upstream;
2. указывает ли changelog пакета на данную CVE (backport дистрибутива уже применён);
3. новее ли кандидат apt установленной версии (существует поддерживаемое исправление);
4. какие работающие процессы отображают `libbrotlidec` и через какую среду выполнения.

Хост получает вердикт `VULNERABLE` только когда версия upstream попадает в уязвимый диапазон
**и** backport отсутствует. Хост получает `SAFE`, когда не выполняется любое из условий — включая
случай, когда ревизия дистрибутива сохраняет внешне уязвимый номер upstream, но уже содержит
исправление.

## 6. Вне области

| Область | Причина |
|---|---|
| Статически слинкованные копии | невидимы для `dpkg`; потребовалось бы сканирование каждого файла как двоичного |
| Образы контейнеров | требуют сканирования на стороне реестра, а не инспекции хоста |
| Envoy, Istio, .NET, Bun, Deno | отдельные жизненные циклы устранения; описаны, но не автоматизированы |
| Хосты Windows и macOS | инструмент работает только с bash и apt |
| Меры на уровне приложения | блокировка `Content-Encoding: br` — временная мера оператора, а не исправление |

## 7. Остаточный риск после устранения

1. Процессы рабочего стола и инфраструктуры сохраняют отображённой старую библиотеку до
   следующего входа или перезагрузки. Они не являются серверным путём декодирования; детектор
   сообщает о них как о `deferred`.
2. Процесс, запущенный из пакета, установленного **после** устранения, но до замены библиотеки,
   унаследовал бы пропатченную библиотеку — порядок действий внутри `remediate.sh` исключает
   обратный случай.
3. Код приложений, несущий собственную копию Brotli (вендоренные исходники, статическая сборка),
   обновлением пакета не затрагивается и должен быть пересобран отдельно.

Порядок действий — см. [PLAYBOOK.ru.md](PLAYBOOK.ru.md), а то, как эти три факта выглядели на
реальных хостах, — см. [FIELD-REPORT.ru.md](FIELD-REPORT.ru.md).
