Уязвим не nginx, а две строки в конфигурации: как устроена CVE-2026-42945 и почему цифры в новостях не бьются
История с CVE-2026-42945 быстро превратилась в типичный инфопожар: в заголовках - "5,7 миллиона уязвимых серверов", рядом - "критическая дыра 9.2 по CVSS", а в качестве вишенки на торте звучит формулировка "пролежала в коде 18 лет". При этом практики, которые начали смотреть реальные конфиги, неожиданно упёрлись в противоположную статистику: один исследователь проверил 1465 конфигураций из 528 популярных репозиториев и не нашёл ни одного примера, похожего на продакшен‑уязвимость; другой прошёлся по 35633 конфигам и обнаружил всего один подходящий - в заброшенном проекте 2011 года. Разница между "миллионами" и "один на десятки тысяч" выглядит так, будто кто-то явно ошибся. Но на деле правы оказываются оба лагеря - просто они измеряют разные вещи.
Патчи вышли 13 мая 2026 года: релизы nginx 1.30.1 и 1.31.0 закрывают уязвимость. По диапазону версий картина неприятная: первая затронутая версия - 0.6.27 (2008 год), последняя - 1.30.0, то есть под удар попадает почти вся история продукта. В коммерческой ветке NGINX Plus в базе NVD фигурируют релизы R32-R36, а исправление обозначено в R37. Если вам нужно быстро понять, почему сегодня многие говорят именно про обновление nginx из-за CVE-2026-42945, то причина простая: уязвимость сидит глубоко (heap overflow) и закрывается только исправлением в коде, а не "хитрой директивой" поверх старой версии.
Отдельного внимания заслуживает, как её нашли. Компания depthfirst прогнала по исходникам nginx собственного ИИ‑агента для аудита низкоуровневого кода: за шесть часов агент отметил пять проблем с памятью, четыре из них разработчики nginx подтвердили, а CVE-2026-42945 оказалась самой серьёзной. Впрочем, в истории фикса есть важная "человеческая" деталь: в самом коммите в поле "кто сообщил" указан инженер Leo Lin - то есть агент нашёл, но в процесс разработки вошёл человек. Кстати, и с "возрастом" бага в публикациях была путаница: кое-где разошлась цифра "16 лет", но корректнее - 18, потому что уязвимая ветка действительно стартует с релиза 2008 года.
Почему оценки CVSS расходятся: "критическая" на бумаге и "средняя" у вендора
Оценки серьёзности разъехались мгновенно. NVD и F5 дают 9.2 по CVSS v4.0 и 8.1 по v3.1, но сам nginx в security advisories отмечает её как medium. Это не "спор о вкусах", а следствие условий эксплуатации: формально у нас переполнение кучи с перспективой RCE, но на практике эксплуатируемость зависит от того, как именно собран ваш location и какие директивы стоят рядом. Отсюда и главный тезис: проблема чаще живёт не "в nginx вообще", а в конкретных сочетаниях конфигурации - буквально в двух строках.
Разбор механики уязвимости упирается в модуль переписывания URL и в то, как nginx подставляет результаты захватов регулярных выражений. Подстановка идёт в два прохода: сначала движок вычисляет, сколько байт займёт итоговая строка, и выделяет буфер; затем во втором проходе копирует данные в выделенную область. Пока обе фазы "думают" одинаково - всё безопасно. Но здесь возникает рассинхрон.
Ключевое место - обработка безымянных захватов регулярного выражения, то есть $1...$9. Если подстановка уходит в аргументы запроса (query string), данные должны быть экранированы: один байт может превратиться в три (пробел → `%20`, плюс → `%2B` и т. д.). Решение, нужно ли экранирование, внутри скриптового движка определяется флагом `is_args`.
Директива `rewrite`, если в строке замены присутствует вопросительный знак, поднимает `is_args`: всё, что после `?`, воспринимается как аргументы. Логика понятная. Но дальше и начинается баг: после завершения обработки rewrite этот флаг должен был быть сброшен, а его "забыли погасить". В итоге `is_args` оставался поднятым до конца обработки location - и это первая половина будущей проблемы.
Вторая половина - директива `set`. Она считает длину значения не тем же самым состоянием, которое будет потом копировать, а через отдельный, только что обнулённый движок, где `is_args = 0`. То есть буфер выделяется под "сырую" длину без запаса на экранирование. А фактическое копирование выполняет основной движок - тот самый, где `is_args` остался поднятым после rewrite, - и он уже экранирует. Получается классика: выделили меньше, записали больше, лишнее ушло за границу выделенной памяти (heap overflow). В коде особенно коварно то, что часть состояния между движками всё-таки переносится (например, `quote` копируют явно), а вот `is_args` - нет. По отдельности каждый фрагмент выглядит разумно, но вместе они дают опасную рассинхронизацию.
Именно из этого вытекает, почему в описаниях так часто подчёркивают "безымянные захваты". Обычные переменные вроде `$myvar` копируются иным кодом - там нет ветки, которая учитывает экранирование в зависимости от `is_args`, поэтому поведение отличается.
Чтобы лучше уложить это в голове, удобно держать перед глазами технический разбор и логику "двух проходов" - в материале про уязвимость nginx CVE-2026-42945 как раз хорошо видно, где рождается несоответствие между расчётом размера и реальной записью.
---
Что на самом деле означает "5,7 миллиона уязвимых серверов"
Шокирующая цифра в новостях обычно относится к количеству публично доступных nginx определённых версий - то есть "потенциально затронутых по коду". Но реальная эксплуатация CVE-2026-42945 требует совпадения нескольких условий в конфигурации и в том, какой запрос прилетает снаружи. Поэтому исследователь, который смотрит "уязвимые версии на баннере", получает миллионы, а тот, кто ищет "уязвимую комбинацию директив", видит единицы на десятки тысяч конфигов. Эта разница не противоречие, а разные модели учёта риска.
Здесь же появляется важная граница, которую часто теряют в пересказах: наличие `rewrite` само по себе ещё не делает сервер уязвимым. Нужна комбинация, при которой флаг `is_args` взводится и продолжает влиять на дальнейшие операции (в том числе на `set`), а запрос должен содержать данные, которые раздуваются при экранировании. То есть "чем набит запрос" действительно влияет на исход: один и тот же конфиг может выглядеть безобидно на обычных URI и становиться опасным на специально подобранной строке.
---
Что сделать прямо сейчас: проверка, обновление и мониторинг
Первое и самое надёжное действие - поставить исправленную версию. Если есть возможность обновляться безболезненно, обновление nginx из-за CVE-2026-42945 стоит планировать как приоритетное: ошибка памяти в веб‑фронтенде - слишком дорогая категория, чтобы спорить с вероятностями.
Второе действие - аудит конфигурации nginx безопасность. В реальном проде rewrite‑правила и set‑переменные со временем обрастают условиями, наследованием и "временными костылями". Именно это создаёт редкие, но взрывоопасные сочетания. Ищите связки, где:
- `rewrite` переводит обработку в режим аргументов (в строке замены есть `?`);
- дальше по цепочке в том же location/контексте фигурируют операции, завязанные на результаты regex‑захватов `$1...$9`;
- значения могут попадать в query string и требовать экранирования.
Третье - наблюдаемость. Даже если вы быстро обновились, полезно уметь замечать попытки: злоумышленник, как правило, будет штурмовать URL, где заметно "раздувание" строки после percent‑encoding, и делать это сериями. На практике помогают: расширенное логирование спорных location, лимиты на необычно длинные URI/аргументы, а также алерты на всплески 400/414/500 в сочетании с длинными строками запроса. Это не "панацея", но часть нормальной защиты nginx от критических уязвимостей, когда вы закрываете не только конкретную дыру, но и класс атак.
Четвёртое - дисциплина вокруг правил переписывания. Там, где возможно, минимизируйте сложные regex‑цепочки и перенос логики из rewrite‑конструкций в более предсказуемые механизмы маршрутизации приложения. А если rewrite необходим, держите его максимально детерминированным и хорошо тестируемым.
Наконец, если вы строите регламент hardening, полезно прямо в чек-лист добавить пункт "настройка nginx для предотвращения RCE": не как магическую директиву, а как набор практик - своевременное обновление, отказ от опасных комбинаций rewrite/set с захватами, ограничение входных размеров, изоляция воркеров (контейнеры/права), и понятная стратегия логирования. Уязвимости уровня heap overflow редко прощают самоуверенность: даже когда вероятность эксплуатации кажется небольшой, цена ошибки обычно максимальная.
---
Итог
CVE-2026-42945 неприятна не "массовой заражённостью", а тем, что это баг класса memory corruption в популярнейшем фронтенде, живший в коде с 2008 года и проявляющийся в конкретных паттернах конфигурации. Поэтому паническая цифра "миллионы" и спокойная статистика "единицы конфигов" могут быть одновременно правдой. Практический вывод простой: обновиться до 1.30.1/1.31.0 (или соответствующего исправления в вашей ветке), затем провести целевой разбор rewrite/set с захватами и подкрутить мониторинг так, чтобы любые странные длинные запросы не проходили незамеченными. И если вам нужно быстро освежить механику флага `is_args` и двухпроходной подстановки, полезно перечитать разбор CVE-2026-42945 в nginx - там наглядно видно, как одна "забытая мелочь" превращается в переполнение кучи.
