CVE-2026-111497 — это и номер уязвимости (запись за границы буфера в декодере Google Brotli, CWE-787), и имя репозитория, в котором лежит агент её устранения: три bash-скрипта, которые по очереди проводят аудит Brotli, чинят найденное и проверяют фактический эффект. Смысл набора не в том, чтобы «обновить пакет» — обновление здесь самая простая часть, — а в том, чтобы ответить на четыре вопроса по каждому хосту и вернуть ответ машиночитаемой строкой вместо абзаца текста, который нельзя перепроверить. Версия 1.2.0, вышедшая 27 октября 2026 года, — релиз документации: отчёт об инциденте разложен по девяти страницам вики, чтобы у каждого вопроса был свой дом, а не одна растущая простыня. Код скриптов в этой версии не менялся.

TL;DR: что это и как проверить за десять минут
- Задача. Понять, действительно ли хост уязвим к CVE-2026-111497, устранить причину и доказать эффект, не перезапуская лишнего.
- Форма. Три bash-скрипта:
detect.sh(только чтение),remediate.sh(единственная точка изменения),verify.sh(только чтение). - Контракт. Коды 0
SAFE, 1VULNERABLE, 3NOT_INSTALLED, 10ERROR; у проверки —VERIFY: PASSилиFAIL. - Проверка. Прогнать детектор на хосте и прочитать одну строку вердикта; при
VULNERABLE— устранение, затем проверка. - Главное ограничение. Только apt и Debian/Ubuntu: rpm, Alpine и контейнерные образы вне области, статически слинкованная копия Brotli для
dpkgневидима.
scp src/common.sh src/detect.sh src/remediate.sh src/verify.sh <host>:/root/cve-2026-111497/
ssh <host> 'bash /root/cve-2026-111497/detect.sh' # код 0/1/3/10
ssh <host> 'bash /root/cve-2026-111497/remediate.sh' # только при VULNERABLE
ssh <host> 'bash /root/cve-2026-111497/verify.sh' # VERIFY: PASS|FAIL
Проблема, которую это решает
Полный аудит Brotli — не проверка версии. По каждому хосту нужно ответить на четыре вопроса: какой пакет установлен, не держат ли работающие процессы уязвимый декодер, какие прикладные пути действительно распаковывают недоверенный Brotli, и является ли backport дистрибутива настоящим исправлением, а не пересборкой того же кода с новым суффиксом. При ручном разборе это десятки вызовов инструментов на хост, а на выходе получается текст, который невозможно воспроизвести.
Самая дорогая ошибка здесь — не пропущенная установка, а ложное «исправлено». Пропатченный файл на диске не патчит уже работающий процесс: библиотека отображена в память, и до перезапуска потребителей хост остаётся уязвимым. Вторая ошибка — принять суффикс версии за доказательство: до обновления security-кармана единственным кандидатом была установленная 1.2.0-3build1, то есть тот же upstream-выпуск, пересобранный дистрибутивом. Пока не прочитан changelog внутри пакета, версия не говорит ничего.
Третья ошибка — перезапустить всё подряд. На гибридных хостах та же libbrotlidec отображается через freetype и fontconfig стеком рабочего стола: GNOME Shell, Xorg, NetworkManager, fwupd, клиент VPN. Их перезапуск обрывает сеанс и туннель, ничего не меняя на серверной поверхности атаки.
Что такое CVE-2026-111497: уязвимость и набор из трёх скриптов
Уязвимость — запись за границы буфера в декодере Google Brotli (c/dec/decode.c, CWE-787). Уязвим именно декодер, а не кодировщик: сервис, который только сжимает ответы, поверхностью атаки не является. Достижимые пути декодирования перечислены в модели угроз:
| Путь декодирования | Типичный носитель |
|---|---|
| Тела 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.
Сам репозиторий — это детерминированный агент: три скрипта и общий модуль, контракт вердиктов, документация (модель угроз, плейбук, полевой отчёт), навык для агента SKILL.md и правила репозитория AGENTS.md. Скрипты не «советуют», а возвращают код возврата и одну строку; модель оркестрирует запуск и не исследует хост вручную.
flowchart TB
DET["src/detect.sh: только чтение"] --> VERDICT["вердикт SAFE / VULNERABLE / NOT_INSTALLED"]
VERDICT --> REM["src/remediate.sh: единственная точка изменения"]
REM --> BACKUP["бэкап /root/cve-2026-111497-fix-<метка>"]
REM --> GATE["гейт подлинности: changelog пакета называет CVE"]
GATE --> INSTALL["apt-get install кандидата из -security"]
INSTALL --> RESTART["перезапуск потребителей libbrotlidec"]
RESTART --> VER["src/verify.sh: только чтение"]
VER --> RESULT["VERIFY: PASS или FAIL"]
STATE[("каталог состояния /var/lib/cve-2026-111497")] --- DET
STATE --- VER| Файл | Ответственность |
|---|---|
src/common.sh |
логирование, разбор версий, матрица классификации, чтение состояния |
src/detect.sh |
аудит только для чтения: вердикт, JSON-отчёт, снимок «до» |
src/remediate.sh |
бэкап, гейт подлинности, сухой прогон, установка, перезапуск, сверка inode |
src/verify.sh |
версия, ссылка на CVE, устаревшие отображения, сбойные юниты, round-trip |
docs/THREAT-MODEL.md |
модель экспозиции путей декодирования |
docs/PLAYBOOK.md |
пошаговая процедура для аудитора-человека |
docs/FIELD-REPORT.md |
результаты с трёх боевых хостов и девять найденных дефектов |
Возможности: аудит Brotli по контракту вердиктов
Возможности набора удобнее читать как ответы на вопросы аудита, а не как список файлов.
Аудит: что установлено и что реально используется
| Что проверяется | Механизм | Зачем |
|---|---|---|
| Установленная и 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 |
отделяет декодирование от сжатия |
| Прикладные примитивы | число файлов с CURLOPT_ENCODING и CURLOPT_ACCEPT_ENCODING |
WordPress, SimplePie и Guzzle принимают все кодировки, включая br |
| Снимок inode «до» | find -type f -printf '%i' по реальному .so |
inode символьной ссылки даёт ложный якорь |
Устранение: бэкап, гейт и перезапуск
| Шаг | Что делает | Инвариант |
|---|---|---|
| Бэкап | /root/cve-2026-111497-fix-<метка>/ со старым .deb, текущими .so и снимком dpkg |
до любого изменения |
| Гейт подлинности | читает changelog кандидата и ищет в нём CVE-2026-111497 |
без совпадения — код 10 и остановка |
| Сухой прогон | показывает, что будет установлено и перезапущено | изменение видно до изменения |
| Установка | apt-get install кандидата из -security |
только apt |
| Перезапуск | серверные службы перезапускаются, рабочий стол — deferred |
сеанс не обрывается |
| Сверка | сравнение inode и повторное сканирование /proc/*/maps |
«перезапущено» подтверждается, а не предполагается |
Проверка: доказательство эффекта
Проверка verify.sh |
Что означает |
|---|---|
| Версия пакета | установлена ожидаемая исправленная версия |
| Ссылка на CVE в changelog | исправление настоящее, а не пересборка |
| Устаревшие отображения | ни один серверный процесс не держит старый inode |
| Сбойные юниты | systemctl --failed пуст |
| Round-trip декодирования | ответ с content-encoding: br распаковывается корректно |
Как это устроено внутри
Порядок шагов зафиксирован полем, а не привычкой: сначала состояние «до», потом изменение, потом проверка эффекта. remediate.sh отказывается работать без предшествующего detect.sh, потому что сравнение «до/после» — единственное доказательство, что перезапуск что-то изменил.
flowchart LR
START["хост Debian или Ubuntu"] --> DETECT{"detect.sh: версия в диапазоне 1.0.3-1.2.0?"}
DETECT -- "нет, backport есть" --> SAFE["код 0: SAFE, закрыть"]
DETECT -- "пакета нет" --> NI["код 3: NOT_INSTALLED, задокументировать"]
DETECT -- "да, backport отсутствует" --> VULN["код 1: VULNERABLE"]
VULN --> REM{"remediate.sh: кандидат называет CVE?"}
REM -- нет --> ERR["код 10: ERROR, эскалация без изменений"]
REM -- да --> FIX["бэкап, установка, перезапуск, сверка inode"]
FIX --> VERIFY{"verify.sh: старая библиотека в /proc отсутствует?"}
VERIFY -- да --> PASS["VERIFY: PASS"]
VERIFY -- нет --> FAIL["VERIFY: FAIL, разбираться до закрытия"]detect.sh -> VERDICT: SAFE|VULNERABLE|NOT_INSTALLED (exit 0/1/3/10)
remediate.sh -> REMEDIATED: <старая версия> -> <новая> (exit 0 или 10)
verify.sh -> VERIFY: PASS|FAIL (exit 0 или 1)
Ключевая деталь — гейт подлинности. В поле конечная точка с changelog дистрибутива отвечала 404, потому что пакет опубликовали несколькими часами ранее; суффикс ubuntu0.1 в версии ничего не доказывал. Доказательство дал сам пакет: security-.deb скачали, распаковали и прочитали usr/share/doc/libbrotli1/changelog.Debian.gz, где нашлась запись с номером CVE и описанием правки декодера. Эта проверка и стала обязательной.
Второй механизм — классификация потребителей. Процессы ищутся по /proc/*/maps; для каждого определяется юнит через cgroup, причём берётся самый внутренний сегмент .service, иначе шаблонные экземпляры вида revoap-worker@1 остаются на старой библиотеке. Демоны панели ISPmanager запускаются загрузчиком панели через временные scope systemd-run, поэтому у них нет собственного юнита и убийство по PID повреждает состояние панели — их перезапускают инструментом панели.
Отдельная тонкость — сравнение версий. dpkg-query отдаёт строку с epoch и ревизией дистрибутива, и если сравнивать её целиком, то 1.2.0-3build1 и 1.2.0-3ubuntu0.1 покажутся разными выпусками upstream, хотя код в них один и тот же с точностью до патча. Поэтому в common.sh версия разбирается по частям: epoch и ревизия отбрасываются, остаётся upstream-номер, который и сравнивается с диапазоном уязвимости. А файл состояния не подключается как shell-скрипт: в строке PRETTY_NAME названия дистрибутивов содержат скобки, и такой файл просто не разберётся — значения читаются по ключу через state_get.
Замеры и цифры
Числа ниже — из полевого отчёта репозитория: три обезличенных боевых хоста и замеры самого релиза 1.2.0. Это выборка, а не перепись парка, и в отчёте это сказано прямо.
| Что измерено | Значение | Где |
|---|---|---|
| Хостов в полевом отчёте | 3 (Ubuntu 26.04, Debian 12, Ubuntu 24.04) | docs/FIELD-REPORT.md |
| Дефектов, найденных полевым прогоном | 9 | там же, раздел 3 |
PHP-файлов с CURLOPT_ENCODING на хосте A |
164 | инвентаризация декодирования |
| Устаревших отображений после устранения | 0 для серверных потребителей на всех трёх | раздел 5 |
| Сайтов, проверенных после устранения (хост A) | 10 из 10 вернули HTTP 200 | раздел 5 |
| Страниц вики после разделения отчёта | 12, все отдают 200 | замеры релиза |
| Гигиена репозитория | 100,0 %, 0 находок | замеры релиза |
| Документы и приватность | 0 ошибок, 0 предупреждений | замеры релиза |
Версии в поле: на хосте A libbrotli1 1.2.0-3build1 → 1.2.0-3ubuntu0.1, на Debian 12 1.0.9-2+b6 → 1.0.9-2+deb12u1, на Ubuntu 24.04 1.1.0-2build2 → 1.1.0-2ubuntu0.1. На всех трёх официальный backport присутствовал в -security, и гейт подлинности проходил до каждой установки.
Отдельно про релиз 1.2.0: это выпуск документации. Отчёт об инциденте разложен по девяти страницам вики — матрица экосистемы, инвентаризация, плейбуки устранения, промежуточные меры, — а дайджест рекомендаций переписан вокруг записи GHSA-3wvj-j6qm-62mr и трёх публичных псевдонимов (Node2Shell, HTTP2Shell, Broccoli2Shell). Между 1.1.0 и 1.2.0 два коммита и тринадцать изменённых файлов; код скриптов не менялся.
Самые дорогие находки поля — те, что давали ложный зелёный результат. Первая: список юнитов на перезапуск формировался правильно, но выводился через printf '%s' без перевода строки, имена склеивались в один несуществующий юнит, systemctl restart получал его, отказ не был фатальным — и каждая служба оставалась на уязвимой библиотеке без единой тревожной строки в выводе. Вторая: проверка «ни один процесс не отображает старый inode» сравнивала с inode символьной ссылки, который по построению не отображается ни в одном процессе, поэтому проверка сообщала об успехе на хосте, который не перезапускался. Обе видны только перекрёстной сверкой утверждения с /proc/*/maps на самом хосте — ни код возврата, ни чтение кода их не выдают.
Почему это круто
- Вердикт вместо рассказа. Агент читает одну строку и код возврата, а не разбирает вывод десятка команд — расход контекста падает на порядок.
- Строка версии не считается доказательством. Гейт читает changelog внутри
.deb, потому что пересборка и настоящее исправление выглядят одинаково, пока не посмотрена ревизия. - Проверяется процесс, а не файл. Утверждение «устранено» подтверждается через
/proc/*/mapsи сравнение inode, а не черезdpkg. - Рабочий стол не страдает. Процессы freetype, Xorg, NetworkManager и VPN помечаются
deferred: пропатченная библиотека подхватится при следующем входе. - У панельного ПО свой путь перезапуска.
mgrctl -m core --restart srvparamвместоkill— состояние панели не повреждается. - Отказ громкий. Если кандидат не называет CVE или совпадает с установленной версией, скрипт останавливается с кодом 10 до любого изменения системы.
- Инварианты записаны, а не подразумеваются.
AGENTS.mdфиксирует «бэкап до изменения», запрет форсировать установку и запрет запускать устранение без аудита. - Полевые дефекты опубликованы. Девять найденных ошибок, включая два случая ложного «успеха», описаны с воспроизведением — это редкость и главная ценность отчёта.
- Вердикты годятся для автоматизации. Четыре кода различают «уязвим», «нет пакета» и «не удалось» — такую задачу можно ставить в cron и разбирать результат машиной, не читая текст вывода.
Установка
| Требование | Значение |
|---|---|
| Целевой хост | Debian 12, Ubuntu 24.04 или Ubuntu 26.04 с apt |
| Доступ | root по SSH-ключу (алиас из ~/.ssh/config) |
| Обязательное | 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-<метка времени>/ |
| Лицензия | MIT |
Скрипты доставляются один раз в каталог на хосте; ставить пакеты на сам хост заранее не нужно.
git clone https://github.com/paulmann/CVE-2026-111497.git
cd CVE-2026-111497
bash -n src/common.sh src/detect.sh src/remediate.sh src/verify.sh
scp src/common.sh src/detect.sh src/remediate.sh src/verify.sh <host>:/root/cve-2026-111497/
Перед доставкой полезно прогнать проверки, которые проект считает обязательными: bash -n, shellcheck src/*.sh и ghagent doc --root ..
Отдельный шаг, который экономит время: убедиться, что хост вообще в области. Дешёвая проверка до копирования файлов снимает половину будущих вопросов.
lsb_release -ds # Debian 12, Ubuntu 24.04 или 26.04
command -v apt-get dpkg systemctl
id -u # 0 — root
apt-cache policy libbrotli1 # есть ли кандидат из -security
Если вместо apt стоит rpm или apk, дальше идти незачем: матрица классификации переносима, а путь устранения — нет. Если libbrotli1 в системе не установлен вообще, детектор вернёт NOT_INSTALLED с кодом 3 — это не ошибка, а состояние, которое надо задокументировать и перепроверить при появлении Brotli в зависимостях.
Настройка
Настраивать в привычном смысле нечего: у набора нет конфигурационного файла, и это осознанно — параметры заданы инвариантами и путями. Меняется только то, что вы решите изменить в скриптах, и тогда правила репозитория требуют пройти проверки и полевой прогон.
flowchart TD
HOST["целевой хост: Debian 12, Ubuntu 24.04 или 26.04"] --> STATE["/var/lib/cve-2026-111497: report.json, state.before, state.after"]
HOST --> BACKUP["/root/cve-2026-111497-fix-<метка>: старый .deb, .so, снимок dpkg"]
HOST --> PAT{"процесс держит libbrotlidec?"}
PAT -- "серверная служба" --> RESTART["перезапуск: nginx, php-fpm, apache2, zabbix, панель"]
PAT -- "рабочий стол, VPN, шрифты" --> DEFER["статус deferred: без перезапуска, до перезагрузки"]
HOST --> PANEL{"демон панели ISPmanager?"}
PANEL -- да --> MGRCTL["mgrctl -m core --restart srvparam"]
PANEL -- нет --> SYSTEMCTL["systemctl restart нужного юнита"]| Что | Значение по умолчанию | Когда меняют |
|---|---|---|
| Каталог состояния | /var/lib/cve-2026-111497/ |
при нестандартной раскладке хоста |
| Каталог бэкапов | /root/cve-2026-111497-fix-<метка>/ |
если /root на отдельном малом разделе |
| Список отложенных шаблонов | DESKTOP_INFRA_PAT |
если в нём оказалась нужная серверная служба |
| Порог классификации der версий | матрица в common.sh |
при появлении нового backport |
| Список потребителей | вычисляется по /proc |
при нестандартных cgroup-раскладках |
Проверка кодов возврата — единственный «язык» этого инструмента, поэтому его стоит держать в голове:
bash detect.sh ; echo "exit=$?" # 0 SAFE, 1 VULNERABLE, 3 NOT_INSTALLED, 10 ERROR
bash remediate.sh ; echo "exit=$?" # 10 до изменения системы, если гейт не пройден
bash verify.sh ; echo "exit=$?" # 1 и строка VERIFY: FAIL — разбираться до закрытия
Подводные камни
- Только apt. Хосты на rpm, Alpine и базовые образы контейнеров вне области: матрица классификации переносима, путь устранения — нет.
- Статическая линковка невидима. Копия Brotli, вкомпилированная в бинарник или образ, для
dpkgне существует; детектор сообщает только о версиях рантаймов, которые может прочитать. - Слоя оркестрации нет. Envoy, Istio, .NET, Bun и Deno описаны в модели угроз, но скрипты их не исправляют — для них нужны свои процедуры.
needrestartможет сработать раньше. На Ubuntu 24.04 пакетный хук перезапускает серверные службы во время установки, и явному шагу перезапуска может быть уже нечего делать; в отчёте такие перезапуски отнесены к хуку.- Рабочий стол и VPN откладываются. Это правильное поведение, но означает, что до перезагрузки часть процессов остаётся на старой библиотеке; при требовании «ноль отображений» нужен перезагрузочный сценарий.
- Полевые данные — три хоста. Отчёт является выборкой, а не переписью парка; поведение на экзотических раскладках не проверено.
Чек-лист внедрения
- Убедиться, что хост в области: Debian 12, Ubuntu 24.04 или 26.04, есть
aptи root по ключу. - Доставить скрипты и прогнать
bash -nплюсshellcheck— синтаксис и линтер до, а не после. - Запустить
detect.sh, зафиксировать вердикт и сохранитьreport.jsonсо снимком «до». - При
VULNERABLEзапуститьremediate.shи проверить, что гейт подлинности нашёл CVE в changelog кандидата. - Запустить
verify.shи добитьсяVERIFY: PASS; отдельно посмотреть строку про отложенные процессы. - Записать в тикет: версию «до/после», число перезапущенных потребителей, число отложенных и что осталось до перезагрузки.
Критерий «работает»: verify.sh печатает VERIFY: PASS, systemctl --failed пуст, серверные процессы не держат старый inode, а сервис, отдающий content-encoding: br, отвечает корректной распаковкой.
FAQ
Это точно про уязвимость в Brotli, а не про сжатие ответов?
Уязвим декодер, а не кодировщик. Сервис, который только сжимает ответы, поверхностью атаки не является; важны пути, где распаковывается недоверенный Brotli: тела запросов, исходящие HTTP-клиенты, прокси-декомпрессоры и встроенные рантаймы.
Почему нельзя просто проверить версию пакета?
Потому что пересборка и настоящее исправление в поле версии выглядят одинаково. Дистрибутив может выпустить тот же upstream-код с новым суффиксом; доказательство даёт только changelog внутри пакета, где назван CVE, — его и читает гейт подлинности.
Что будет, если запустить устранение на хосте с рабочим столом?
Скрипт классифицирует процессы рабочего стола и VPN как deferred: отчёт их назовёт, перезапуска не будет, пропатченная библиотека загрузится при следующем входе или перезагрузке. Сеанс и туннель не обрываются.
Почему демоны панели перезапускаются отдельной командой?
Потому что ISPmanager запускает их собственным загрузчиком через временные scope systemd-run: у них нет юнита, и остановка по PID повреждает состояние панели. Поддерживаемый путь — mgrctl -m core --restart srvparam.
Подходит ли набор для контейнеров и rpm-хостов?
Нет. Область — Debian и Ubuntu с apt; для rpm и Alpine переносима матрица классификации, но не путь устранения. Статически слинкованная копия Brotli не видна dpkg в любом случае.
Что нового в версии 1.2.0, если код не менялся?
Документация: отчёт об инциденте разложен на девять страниц вики (матрица экосистемы, инвентаризация, плейбуки устранения, промежуточные меры), переписан дайджест рекомендаций вокруг GHSA-3wvj-j6qm-62mr и трех публичных псевдонимов, обновлены разделы операций и ловушек.
Чем это отличается от обычного apt upgrade?
apt upgrade меняет файл на диске и ничего не знает о том, кто уже держит старую библиотеку в памяти, и не проверяет, что кандидат действительно исправляет CVE, а не пересобран из того же кода. Набор добавляет к обновлению три вещи: доказательство подлинности пакета, перезапуск именно тех потребителей, которые можно перезапустить, и проверку эффекта в /proc.
Итог
Набор решает узкую задачу так, как её и надо решать в эксплуатации: сначала состояние «до», потом единственная точка изменения, потом доказательство эффекта. Главная ценность здесь даже не в трёх скриптах, а в двух решениях — читать changelog вместо версии и проверять /proc/*/maps вместо dpkg. Полевой отчёт добавляет третье: девять дефектов, два из которых давали ложный «успех», найдены запуском, а не чтением кода. Если у вас есть парк Debian/Ubuntu-хостов с Brotli в декодерах, начинать стоит с одного хоста и detect.sh — это ничего не меняет в системе и сразу показывает, есть ли работа. Дальше решение принимается по вердикту, а не по интуиции: код 0 закрывает вопрос, код 1 даёт право на устранение, код 3 требует перепроверки, код 10 — эскалации без самодеятельности.
Цитата: Уязвимость закрывается обновлением пакета, а инцидент — только доказательством того, что ни один процесс не держит старую библиотеку в памяти.
Связанные материалы
- CVE-2026-111497 — репозиторий — скрипты, модель угроз, плейбук, полевой отчёт и правила репозитория.
- Релиз v1.2.0 — разделение отчёта об инциденте на девять страниц и замеры перед выпуском.
- Вики проекта — кейсы, дайджест рекомендаций и операционный runbook.
- docs/FIELD-REPORT.ru.md — три хоста, девять дефектов и свидетельства проверки.
- docs/THREAT-MODEL.ru.md — модель экспозиции путей декодирования.
LLM Summary
- Тема:
CVE-2026-111497— набор из трёх bash-скриптов для аудита, устранения и проверки уязвимости в декодере Google Brotli (запись за границы буфера, CWE-787). - Что делает:
detect.shтолько читает и выдаёт вердикт,remediate.sh— единственная точка изменения с бэкапом и гейтом подлинности,verify.shдоказывает фактический эффект. - Форма: shell-скрипты плюс документация (модель угроз, плейбук, полевой отчёт), навык
SKILL.mdи правилаAGENTS.md; лицензия MIT. - Контракт: коды 0
SAFE, 1VULNERABLE, 3NOT_INSTALLED, 10ERROR; проверка печатаетVERIFY: PASSилиFAIL. - Ключевые команды:
bash src/detect.sh,bash src/remediate.sh,bash src/verify.sh,bash -n src/*.sh,shellcheck src/*.sh. - Требования: Debian 12, Ubuntu 24.04 или 26.04 с
apt, root по SSH-ключу,bash5.x,dpkg,systemd; состояние в/var/lib/cve-2026-111497/, бэкапы в/root/cve-2026-111497-fix-<метка>/. - Замеры: три боевых хоста, 164 PHP-файла с
CURLOPT_ENCODINGна одном из них, ноль устаревших серверных отображений после устранения, десять из десяти сайтов ответили 200; релиз 1.2.0 проверен на 12 страницах вики. - Ограничения: только apt, нет обнаружения статической линковки, нет слоя оркестрации для Envoy/Istio/.NET/Bun, процессы рабочего стола помечаются
deferred, полевые данные — выборка из трёх хостов. - Ссылки: https://github.com/paulmann/CVE-2026-111497, https://github.com/paulmann/CVE-2026-111497/releases/tag/v1.2.0
Промт для агента (установка и настройка)
Готовый промт для AI-агента: скопируйте блок целиком кнопкой и отдайте своему ассистенту. Шаги и команды взяты из AGENTS.md и «Быстрого старта» README репозитория — это инструкция автора для агентов, а не пересказ.
Задача: провести аудит, устранение и проверку CVE-2026-111497 на хосте Debian или Ubuntu, не ломая рабочий сеанс.
Материалы:
- репозиторий: https://github.com/paulmann/CVE-2026-111497
- релиз: https://github.com/paulmann/CVE-2026-111497/releases/tag/v1.2.0
- правила репозитория (прочитать первой): https://github.com/paulmann/CVE-2026-111497/blob/main/AGENTS.ru.md
- модель экспозиции: docs/THREAT-MODEL.ru.md
- полевые уроки: docs/FIELD-REPORT.ru.md
Приоритет: безопасность важнее скорости; любому необратимому действию предшествуют резервная копия и проверка той же операции в песочнице.
Границы ответственности из AGENTS.md:
- src/detect.sh — только чтение, не меняет пакеты, службы и конфигурацию;
- src/remediate.sh — единственная точка изменения: бэкап, гейт подлинности, сухой прогон, установка, перезапуск;
- src/verify.sh — только чтение, подтверждает фактически достигнутый эффект.
Подготовка и проверки перед доставкой:
bash -n src/common.sh src/detect.sh src/remediate.sh src/verify.sh
shellcheck src/*.sh
ghagent doc --root .
Доставка и порядок (порядок фиксирован: detect -> remediate -> verify):
scp src/common.sh src/detect.sh src/remediate.sh src/verify.sh <host>:/root/cve-2026-111497/
ssh <host> 'bash /root/cve-2026-111497/detect.sh' ; echo "exit=$?"
ssh <host> 'bash /root/cve-2026-111497/remediate.sh'
ssh <host> 'bash /root/cve-2026-111497/verify.sh'
Трактовка кодов возврата detect.sh: 0 SAFE — задокументировать и закрыть; 1 VULNERABLE — запускать устранение; 3 NOT_INSTALLED — задокументировать и перепроверить при появлении Brotli; 10 ERROR — прочитать сообщение и эскалировать, не форсировать.
Запрещено (AGENTS.md):
- запускать remediate.sh без предшествующего detect.sh: состояние «до» обязательно;
- форсировать установку пакета, когда проверка подлинности не пройдена;
- удалять файлы, которые задача не упоминает, без явного согласия владельца;
- включать автоматическое обновление или перезагрузку без присмотра на целевом хосте;
- перезапускать демоны панели через kill: путь панели — mgrctl -m core --restart srvparam.
Ловушки, о которых предупреждает репозиторий:
- подключение файла состояния как shell даёт синтаксическую ошибку — читать значения через state_get;
- inode по glob даёт inode символьной ссылки и ложно проходит проверку — find -type f -printf '%i';
- printf '%s' без перевода строки в цикле по юнитам склеивает имена и делает перезапуск холостым — printf '%s\n';
- systemctl restart юнита рабочего стола рвёт сеанс и VPN — такие процессы в DESKTOP_INFRA_PAT и помечаются deferred.
Что считать успехом: detect.sh вернул 0 или 1 с понятным вердиктом; remediate.sh прошёл гейт подлинности и создал бэкап; verify.sh напечатал VERIFY: PASS; systemctl --failed пуст; серверные процессы не держат старый inode; сервис с content-encoding: br отвечает корректной распаковкой.