# CVE-2026-111497 — агент аудита и устранения (Brotli)

**Детерминированные аудит, устранение и проверка для CVE-2026-111497 — записи за границы буфера в декодере Google Brotli: три shell-скрипта возвращают вердикт, результат устранения и результат проверки, а модель читает по одной строке вместо исследования хоста.**

<!-- md-i18n:switcher -->
**На других языках:** [English](README.md) · [Deutsch](README.de.md) · [中文](README.zh.md) · [हिन्दी](README.hi.md) · [Español](README.es.md) · Русский

[![CI](https://github.com/paulmann/CVE-2026-111497/actions/workflows/ci.yml/badge.svg)](https://github.com/paulmann/CVE-2026-111497/actions/workflows/ci.yml)
[![Release](https://img.shields.io/github/v/release/paulmann/CVE-2026-111497)](https://github.com/paulmann/CVE-2026-111497/releases)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Shell: bash](https://img.shields.io/badge/shell-bash-4EAA25.svg)](#требования)
[![Platform: Debian/Ubuntu](https://img.shields.io/badge/platform-Debian%20%7C%20Ubuntu-A80030.svg)](#требования)

![CVE-2026-111497 — агент устранения Brotli](assets/social-preview.svg)

Детерминированный детектор, средство устранения и проверки для **CVE-2026-111497** — записи за
границы буфера в декодере Google Brotli (`c/dec/decode.c`, CWE-787). Три shell-скрипта выполняют
полный аудит и возвращают компактный вердикт; языковая модель оркестрирует запуск и читает одну
строку вместо ручного исследования хоста.

## Содержание

- [Зачем это нужно](#зачем-это-нужно)
- [Модель экспозиции](#модель-экспозиции)
- [Быстрый старт](#быстрый-старт)
- [Вердикты и коды возврата](#вердикты-и-коды-возврата)
- [Что проверяет аудит](#что-проверяет-аудит)
- [Структура репозитория](#структура-репозитория)
- [Требования](#требования)
- [Ограничения](#ограничения)
- [Документация](#документация)
- [Языки](#языки)
- [Участие](#участие)
- [Лицензия](#лицензия)

[Wiki](https://github.com/paulmann/CVE-2026-111497/wiki) · [Changelog](CHANGELOG.md) · [Security](SECURITY.md) · [English](README.md)

## Зачем это нужно

Полный аудит Brotli — не проверка версии. По каждому хосту нужно ответить на четыре вопроса:
какой пакет установлен, не держат ли работающие процессы уязвимый декодер, какие прикладные пути
действительно распаковывают недоверенный Brotli и является ли backport дистрибутива настоящим
исправлением, а не пересборкой.

При ручном разборе эти вопросы стоят десятков вызовов инструментов на хост, а ответ приходит
текстом, который невозможно перепроверить. Здесь на них отвечают скрипты с фиксированным
контрактом кодов возврата:

| Команда | Влияние на хост | Вывод для агента |
|---|---|---|
| `detect.sh` | только чтение | `VERDICT: SAFE\|VULNERABLE\|NOT_INSTALLED` |
| `remediate.sh` | единственная точка изменения | `REMEDIATED: <старая> -> <новая>` |
| `verify.sh` | только чтение | `VERIFY: PASS\|FAIL` |

## Модель экспозиции

Уязвим **декодер**, а не кодировщик. Сервисы, которые только сжимают ответы Brotli, не являются
поверхностью атаки; ею являются сервисы, распаковывающие недоверенный Brotli.

| Достижимый путь декодирования | Типичный носитель |
|---|---|
| Тела HTTP-запросов | `Content-Encoding: br` в сторону приложения |
| Исходящие HTTP-клиенты | `fetch()`, libcurl с пустым `CURLOPT_ENCODING` (принимает всё) |
| Ответы через прокси | декомпрессоры Envoy/Istio |
| Загружаемые архивы | потоковое декодирование Brotli в приложении |
| Встроенные рантаймы | Node.js, Bun, Python `Brotli`/`brotlicffi`, декомпрессия запросов в .NET |

Уязвимые версии upstream — **с 1.0.3 по 1.2.0**. Исправленные — **1.0.10, 1.1.1 и 1.2.1**
(выпущены 21 октября 2026 года), а также любой backport дистрибутива, в changelog которого указан
этот CVE.

## Быстрый старт

```bash
# 1. Доставить скрипты один раз (хост — алиас из ~/.ssh/config)
scp src/common.sh src/detect.sh src/remediate.sh src/verify.sh <host>:/root/cve-2026-111497/

# 2. Аудит — только чтение
ssh <host> 'bash /root/cve-2026-111497/detect.sh'          # код 0/1/3/10

# 3. Устранение — только при вердикте VULNERABLE
ssh <host> 'bash /root/cve-2026-111497/remediate.sh'

# 4. Проверка фактического эффекта
ssh <host> 'bash /root/cve-2026-111497/verify.sh'          # VERIFY: PASS|FAIL
```

## Вердикты и коды возврата

| Код | Вердикт | Значение | Действие |
|---:|---|---|---|
| 0 | `SAFE` | установленная версия вне уязвимого диапазона либо backport уже применён | задокументировать и закрыть |
| 1 | `VULNERABLE` | upstream-версия в уязвимом диапазоне, backport отсутствует | запустить `remediate.sh` |
| 3 | `NOT_INSTALLED` | `libbrotli1` на хосте отсутствует | задокументировать; перепроверить при появлении Brotli |
| 10 | `ERROR` | нарушено предусловие или инвариант | прочитать сообщение, эскалировать, не форсировать |
| 1 (`verify.sh`) | `FAIL` | устранение не дало эффекта | разобраться до закрытия инцидента |

`remediate.sh` останавливается с кодом 10 до любого изменения системы, если кандидат apt совпадает
с установленной версией или changelog кандидата не ссылается на `CVE-2026-111497`.

## Что проверяет аудит

| Проверка | Механизм | Зачем нужна |
|---|---|---|
| Установленная и upstream-версия | `dpkg-query`, epoch и ревизия отбрасываются | ревизия дистрибутива скрывает upstream-номер |
| Применённый backport | упакованный `changelog.Debian.gz` с упоминанием CVE | достоверный признак, а не строка версии |
| Кандидат apt | `apt-get update`, затем `apt-cache policy` | решает, существует ли поддерживаемое исправление |
| Живые потребители | поиск `libbrotlidec` по `/proc/<pid>/maps` | пропатченный файл не патчит работающий процесс |
| Поверхность декодирования | Brotli в libcurl, модули Node/Bun/Python/PHP, `ngx_brotli`, `mod_brotli` | отделяет пути декодирования от кодирования |
| Прикладные примитивы декодирования | число PHP-файлов с `CURLOPT_ENCODING` / `CURLOPT_ACCEPT_ENCODING` | WordPress, SimplePie и Guzzle принимают все кодировки, включая `br` |
| Снимок inode «до» | `find -type f -printf '%i'` по реальному `.so` | inode символьной ссылки даёт ложный якорь |

## Структура репозитория

```text
src/
  common.sh      логирование, разбор версий, матрица классификации, state_get
  detect.sh      аудит только для чтения: вердикт, JSON-отчёт, снимок «до»
  remediate.sh   бэкап, гейт подлинности, сухой прогон, установка, перезапуск, сверка inode
  verify.sh      версия, ссылка на CVE, устаревшие отображения, сбойные юниты, round-trip
docs/
  THREAT-MODEL.md  модель экспозиции путей декодирования и поверхность атаки
  PLAYBOOK.md      пошаговая процедура для аудитора-человека
  FIELD-REPORT.md  обезличенные результаты с трёх боевых хостов
wiki/             документация оператора: кейсы, дайджест рекомендаций, runbook
SKILL.md          навык агента: минимальный оркестрационный плейбук
AGENTS.md         правила и инварианты репозитория
```

## Требования

- Целевой хост: Debian 12, Ubuntu 24.04 или Ubuntu 26.04 с `apt`, root по SSH-ключу.
- `bash` 5.x, `dpkg`, `apt-get`, `systemd`; `curl` и `brotli` необязательны и лишь расширяют
  функциональный round-trip.
- Сетевой доступ только к зеркалам пакетов дистрибутива.
- Каталог состояния: `/var/lib/cve-2026-111497/` (`report.json`, `state.before`, `state.after`).
- Бэкапы: `/root/cve-2026-111497-fix-<метка времени>/` со старым `.deb`, текущими `.so` и снимком
  `dpkg`.

## Ограничения

- **Только apt.** Хосты на rpm, Alpine и базовые образы контейнеров вне области: матрица
  классификации переносима, путь устранения — нет.
- **Нет обнаружения статической линковки.** Копия Brotli, вкомпилированная в бинарник или образ,
  для `dpkg` невидима. Детектор сообщает только те версии рантаймов, которые может прочитать.
- **Нет слоя оркестрации.** Envoy, Istio, .NET, Bun и Deno описаны в модели угроз, но скрипты их
  не исправляют.
- **Процессы рабочего стола и инфраструктуры откладываются, а не перезапускаются.** Шрифтовой и
  графический стек отображают `libbrotlidec` через freetype; их перезапуск оборвал бы сессию. Они
  помечаются как `deferred` и загружают патченную библиотеку при следующем входе или перезагрузке.
- **`needrestart` может сработать раньше.** На Ubuntu 24.04 пакетный хук перезапускает серверные
  службы во время установки, поэтому шагу перезапуска может быть уже нечего делать.
- **Полевые данные — три хоста.** Отчёт является выборкой, а не переписью парка.

## Документация

| Документ | Содержание |
|---|---|
| [`docs/THREAT-MODEL.ru.md`](docs/THREAT-MODEL.ru.md) | модель экспозиции, инвентаризация путей декодирования, обоснование тяжести |
| [`docs/PLAYBOOK.ru.md`](docs/PLAYBOOK.ru.md) | процедура, которую реализуют скрипты, для аудитора-человека |
| [`docs/FIELD-REPORT.ru.md`](docs/FIELD-REPORT.ru.md) | три хоста, девять дефектов, найденных полем, доказательства проверки |
| [Wiki](https://github.com/paulmann/CVE-2026-111497/wiki) | кейсы с причинами дефектов, дайджест рекомендаций, операционный runbook (на английском) |

## Языки

Английский — канонический язык: документ без суффикса языка является источником истины. Каждый
перевод несёт суффикс своего языка и ссылается на канонический файл.

| Язык | Файлы |
|---|---|
| Английский (канон) | `README.md`, `AGENTS.md`, `SKILL.md`, `docs/*.md` |
| Русский | `*.ru.md` |
| Немецкий | `*.de.md` |
| Испанский | `*.es.md` |
| Китайский | `*.zh.md` |
| Хинди | `*.hi.md` |

Changelog и wiki по решению проекта остаются только на английском: журнал выпусков и справочник
оператора ведутся в одном источнике, а отставший перевод хуже отсутствующего.

## Участие

Исправления и новые backport-версии приветствуются. Сначала прочитайте
[`CONTRIBUTING.md`](CONTRIBUTING.md): контракт кодов возврата, правило «бэкап до изменения» и гейт
подлинности не обсуждаются. Отчёты об уязвимостях — по [`SECURITY.md`](SECURITY.md).

## Лицензия

MIT. Инструмент оборонительный; он не содержит учётных данных, идентификаторов инфраструктуры и
адресов целей.
