WordPress CVE-2026-119977: код на сайте исполняется, пока обновляется ядро
Третьего ноября 2026 года CISA внесла CVE-2026-119977 в каталог уязвимостей с подтверждённой эксплуатацией, а срок устранения для федеральных агентств США поставила на 6 ноября. Гонка в механизме обновления ядра WordPress: пока сайт обновляется, тот, кто дотянулся до каталога wp-content/upgrade/, получает выполнение кода. Ни аккаунта, ни действия администратора не нужно — попасть в момент обновления.
Что сломано
Обновление ядра раскладывает новые файлы в wp-content/upgrade/ и оттуда переносит их на место. Каталог доступен по HTTP, а последовательность «заполнить — перенести» не атомарна: в окне обновления там лежат файлы, которые сайт исполняет. NVD описывает это как CWE-367, гонку между проверкой и использованием.
CVSS 8.1: сеть, высокая сложность, привилегий нет, участия пользователя нет. Высокая сложность не утешает: окно возникает при каждом полном обновлении — и когда кнопку нажимаете вы, и когда работает автообновление.
Кого касается
Уязвимы версии с 4.7 по 7.1.3 включительно — все ветки от 4.7 до 7.x. «Стабильная» ветка не защищает. Исправленные релизы:
WordPress 7.1.4 вышел 28 октября 2026 года как security release; для остальных веток бэкпорты вышли отдельными релизами, полный список — в записи NVD.
Как закрыть
бэкап;
обновление ядра до исправленного релиза;
проверка, что версия действительно изменилась;
запрет веб-доступа к каталогу обновления.
Каталог wp-content/upgrade/ — страховка на те минуты, пока сайт не обновлён. Это не замена обновлению.
location ^~ /wp-content/upgrade/ { deny all; }
Это для nginx. На Apache и LiteSpeed каталог закрывает блок в .htaccess, и инструмент ниже дописывает его сам. После обновления загляните в каталог: чужой .php — инцидент, а не мусор; файл сохраняют, хост считают скомпрометированным.
Инструмент, который делает это за вас
Bash WP-CLI Update 8.1.1 — bash-обвязка над WP-CLI для парка сайтов, MIT. Нужны bash 4.2+, WP-CLI и root. Ставится как npm install -g bash-wp-cli-update или через install.sh из релиза.
Оценка ничего не меняет: wp-cli-update --security --json-lines сравнивает версию ядра каждого сайта с таблицей исправленных релизов и печатает строку на сайт (site, core, cve, status, fix). Код возврата 1 — есть сайт, который нужно обновить, или версия не читается.
wp-cli-update --security --json-lines
wp-cli-update --full -j 4 --backup db --harden-upgrade-dir --report /var/log/wp-cli-update/cve.json
wp-cli-update --security --json-lines
Вторая команда обновляет ядро, плагины и темы, сначала дампит базы, а --harden-upgrade-dir дописывает в .htaccess маркерный deny-блок (старый файл сохраняется как .htaccess.wp-cli-update.bak). Третья — доказательство: код 0 значит, что осмотренные сайты на исправленных версиях.
Чего инструмент не делает:
не правит конфигурацию nginx — директиву только печатает;
не патчит WordPress вместо вендора;
не прибирает последствия компрометации;
сайт на ветке, которой нет в таблице, помечает как требующий обновления, даже если бэкпорт уже вышел.
Заключение
Проверил на живом парке: 24 установки WordPress, две сидели на 7.1.3. --security до обновления — exit 1; --core с дампом баз поднял обе до 7.1.4: 24/24 ok, exit 0, 105 секунд, бэкапы 1,76 и 1,51 МБ. Повторный --security — 24/24 safe, exit 0. Каталог wp-content/upgrade/ был закрыт nginx-правилом ещё до обновления: снаружи 403. --harden-upgrade-dir не использовался — он правит .htaccess, а здесь nginx.
Непроверенными остались промежуточные ветки (6.x и 5.x в парке не было) и путь .htaccess для Apache. Начать стоит с --security: это чтение, оно ничего не меняет.