Обновлять WordPress на десятках сайтов скриптом — привычное дело; но между «обновил» и «обновил успешно» есть разница, и в этот раз она стала главной темой релиза. Версия 8.1.0 — security-выпуск: в нём появилась проверка CVE-2026-119977 прямо в инструменте — режим --security только читает версии ядра и говорит, кто уязвим (и годится для мониторинга раз в минуту, потому что не берёт ни блокировку, ни бэкап), а --harden закрывает веб-доступ к wp-content/upgrade/. Заодно обычный прогон --core/--full больше не считает успехом сам факт запуска, а лицензия сменилась на MIT. Ниже — что именно изменилось, как это проверить и где легко ошибиться с кодами выхода: в моих замерах --security без установленного WP-CLI вернул 3, а не 0 и не 1.

bash wp cli update 8 1 0 cover

TL;DR: что нового и как проверить

  1. --security (только чтение). Читает версию ядра каждого сайта, сравнивает с исправленными выпусками для CVE-2026-119977, печатает вердикт по сайту. Код 1 — есть уязвимый или нечитаемый сайт, код 0 — все на исправленной версии.
  2. --harden. Добавляет в .htaccess сайта блок, запрещающий доступ к wp-content/upgrade/; прежний файл один раз копируется в .htaccess.wp-cli-update.bak; для nginx директива печатается в конце прогона, потому что nginx .htaccess не читает.
  3. HARDEN_UPGRADE_DIR. Тот же блок можно включать в каждый пишущий режим; по умолчанию выключен, а --security, --health и --check отвергают флаг с кодом 2.
  4. Колонка CVE в --health. Значения safe, UPDATE или ?, плюс поле cve_2026_119977 в JSON Lines — мониторинг видит уязвимость без разбора текста.
  5. Лицензия MIT. Коммерческое использование больше не требует отдельного соглашения.
bash -n Bash_WP-CLI_Update.sh        # синтаксис, у меня OK
bash Bash_WP-CLI_Update.sh --help    # версия и список режимов
bash Bash_WP-CLI_Update.sh --check   # окружение; код 3, если нет wp
bash Bash_WP-CLI_Update.sh --security # код 1, если есть уязвимый сайт

Что нового в 8.1.0

Что добавлено Зачем Ограничение
--security найти сайты ниже исправленной версии ядра только чтение, без блокировки и бэкапа
--harden закрыть wp-content/upgrade/ от веба Apache и LiteSpeed; для nginx — директива в выводе
--harden-upgrade-dir / --no-harden-upgrade-dir включать блок в пишущих режимах по умолчанию 0
HARDEN_UPGRADE_DIR то же через конфигурацию отвергается в read-only режимах
Колонка CVE в --health видеть статус в инвентаризации значения safe / UPDATE / ?
Поле cve_2026_119977 в JSON Lines машинная обработка отчёта —
flowchart TB
  HOST["хост с несколькими сайтами"] --> SEC["--security: чтение версии ядра"]
  SEC --> CMP{"версия ниже исправленной?"}
  CMP -- да --> EX1["вердикт UPDATE, код выхода 1"]
  CMP -- нет --> EX0["вердикт safe, код 0"]
  HOST --> HARD["--harden: блок в .htaccess, копия .bak"]
  HARD --> APACHE["Apache и LiteSpeed: RewriteRule F"]
  HARD --> NGINX["nginx: директива печатается, .htaccess не читает"]
  HOST --> HEALTH["--health: колонка CVE в отчёте"]

Отдельно стоит сказать про саму уязвимость, ради которой всё это: CVE-2026-119977 — состояние гонки в штатном обновляторе ядра WordPress, CVSS 8.1, в каталоге эксплуатируемых уязвимостей CISA с 03.11.2026. Затронуты ядра с 4.7 по 7.1.3; исправленные выпуски — 7.1.4, 7.0.8 на ветке 7.0, 6.9.11 на ветке 6.9 и 4.7.39 на ветке 4.7. Для 4.6 и старше исправления нет — такие сайты закрывать или переносить, а не «подождать патч».

Ключевые изменения

Прогон больше не считает себя успешным по факту запуска

Прежняя логика была простой: команда выполнилась — значит, обновили. Теперь --core и --full проверяют результат и, если сайт остался ниже исправленного выпуска, пишут это в журнал с номером CVE и версией, до которой нужно дойти. Разница принципиальная: «обновление не удалось, но ошибки не было» — самый частый способ оставить сайт уязвимым на недели.

Проверка не мешает мониторингу

--security не берёт блокировку и не делает бэкап — поэтому его можно вызывать хоть каждую минуту, из Zabbix или cron, не рискуя наложением на плановое обновление. Это редкое и правильное разделение: у режима чтения своя цена и свой контракт.

Закрытие каталога обновлений

--harden добавляет маркированный блок в .htaccess корня сайта:

# wp-cli-update: harden upgrade dir
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteRule ^wp-content/upgrade/ - [F,L]
</IfModule>
# /wp-cli-update: harden upgrade dir

Блок идемпотентен: повторный запуск не плодит копии, а прежний .htaccess один раз сохраняется как .htaccess.wp-cli-update.bak. Для nginx в конце прогона печатается строка, которую нужно положить в конфиг сайта:

location ^~ /wp-content/upgrade/ { deny all; }

Лицензия и документация

Лицензия стала MIT — это снимает вопрос «а можно ли в коммерции», который раньше требовал отдельного соглашения. AGENTS.md из большого файла превратился в карту: две непререкаемых правила, таблица файлов, краткий порядок проверки и ссылки на подробные документы (docs/AGENT-INSTALL.md, docs/AGENT-OPERATIONS.md, docs/DEVELOPMENT.md). Практический смысл — инструктаж агента перестал быть простынёй на сотни строк, которую никто не читает целиком.

Замеры и цифры

Снято 08.11.2026 на Windows с Git Bash, архив релиза распакован, сайтов нет — проверял поведение оболочки и коды выхода.

Что измерено Значение Как
SHA-256 архива bash-wp-cli-update-8.1.0.tar.gz 0d9b268b…58ba, совпал с SHA256SUMS Get-FileHash против файла из релиза
Размер архива 183 080 байт загрузка gh release download
Синтаксис bash -n — чисто Git Bash
Версия в --help 8.1.0 запуск --help
Режимов в справке 25 строк режимов и опций, включая --security, --harden, --doctor, --completion разбор вывода --help
--check без WP-CLI сообщение WP-CLI not found … set WP_CLI_PATH, код 3 запуск с замером $?
--security без WP-CLI то же сообщение, код 3 там же
Bash WP-CLI Update 8.1.0: что проверено запуском и как читать коды выхода

Главный вывод из замеров — про коды: 3 — это ошибка окружения, а не «сайт уязвим». Если мониторинг ловит только ненулевой код, он будет путать «нет wp-cli на хосте» с «сайт ниже исправленной версии». Различать надо явно: 1 — уязвимый сайт, 2 — неверное сочетание флагов, 3 — окружение.

Чего замеры не показывают: реального обновления сайтов и работы --harden на живом Apache — сайтов под рукой не было, а на Windows-хосте .htaccess ничего не значит. Эти части — по заметкам к релизу и коду; их стоит проверять на своём стенде.

Установка и обновление

flowchart LR
  A["скачать архив релиза"] --> B["сверить SHA256SUMS"]
  B --> C["распаковать поверх прежней копии"]
  C --> D["--check: окружение и сайты"]
  D --> E{"код 0?"}
  E -- "3" --> F["нет WP-CLI или путь не тот"]
  E -- "0" --> G["--security: кто уязвим"]
  G --> H["--core или --full: обновление ядра"]
  H --> I["--harden: закрыть каталог обновлений"]
# архив из релиза и сверка контрольной суммы
gh release download v8.1.0 -R paulmann/Bash_WP-CLI_Update -D ./rel
cd ./rel && sha256sum -c SHA256SUMS

# распаковать поверх прежней копии и проверить окружение
tar -xzf bash-wp-cli-update-8.1.0.tar.gz -C /opt/wp-update --strip-components=1
/opt/wp-update/Bash_WP-CLI_Update.sh --check
Шаг Команда Ожидание
Синтаксис и версия bash -n … && … --help без ошибок, 8.1.0 в первой строке
Окружение --check код 0; код 3 — нет WP-CLI или путей
Кто уязвим --security код 1 при наличии сайта ниже исправленной версии
Обновление --core или --full в журнале нет строк «остался ниже»
Защита каталога --harden блок в .htaccess, рядом .htaccess.wp-cli-update.bak
Проверка --health колонка CVE без UPDATE

Проверка после обновления

flowchart TD
  R["запуск"] --> Z{"код выхода"}
  Z -- 0 --> OK["всё в порядке: обновлено или уже безопасно"]
  Z -- 1 --> WARN["есть сайт ниже исправленной версии"]
  Z -- 2 --> USE["неверное сочетание флагов"]
  Z -- 3 --> ENV["окружение: нет wp, нет путей"]

Четыре проверки, каждая с однозначным результатом:

  1. --help показывает 8.1.0 — значит, запускается новая копия, а не старая из PATH.
  2. --check даёт код 0. Код 3 — не поломка сайта, а отсутствие wp или неверный WP_CLI_PATH.
  3. --security даёт код 0 на всех сайтах группы. Код 1 — есть работа: смотреть, какой сайт и какую версию ядра он держит.
  4. --health в JSON Lines содержит cve_2026_119977 со значением safe — если поле есть, мониторинг можно строить на нём, не разбирая текст.

Совместимость

Что Состояние
Лицензия MIT (было — отдельное соглашение для коммерции); архив legacy/ сохраняет прежнюю
Ядра WordPress инструмент работает с 4.7+; для уязвимости исправления есть на ветках 7.1, 7.0, 6.9, 4.7
Чего нет в 8.1.0 изменений менеджера, поисковика, режимов, опций, ключей конфигурации и кодов выхода
8.1.1 только тесты: починен рекордер в test_fleet.sh; поведение инструмента не менялось
nginx .htaccess не читается: нужна директива location ^~ /wp-content/upgrade/ { deny all; }

Версия 8.1.1, вышедшая через полтора часа, — чисто тестовый патч. Причина в заметках описана честно: фальшивый wp в тестах собирал строку четырьмя вызовами printf внутри перенаправленной группы, при -j 5 записи накладывались, и проверка «ожидалось 5 вызовов» видела 4. Запись собрана в переменную и печатается одним printf. Ни одного изменения в самом инструменте эта версия не несёт.

Подводные камни

  • Код 3 читают как «уязвим». Проверено: без WP-CLI и --check, и --security возвращают 3. Уязвимый сайт — это 1. Если алерт не различает 1 и 3, дежурный будет искать дыру там, где на хосте просто не установлен wp.
  • --harden не работает на nginx. Он честно печатает директиву, но применять её нужно в конфиге сайта; .htaccess там игнорируется.
  • HARDEN_UPGRADE_DIR в read-only режимах отвергается с кодом 2. Это не ошибка конфигурации, а защита от «включил везде не глядя».
  • --security не обновляет. Он только смотрит: ни блокировки, ни бэкапа, ни изменений. Ждать от него лечения уязвимости нельзя.
  • 4.6 и старше исправления не получат. Если такие сайты в парке есть, обсуждать надо не «когда обновим», а перенос или закрытие.
  • .htaccess копируется один раз. Второй прогон не перезапишет .bak — при ручных правках помнить, что рядом лежит не свежая копия.
  • Колонка CVE со значением ?. Это «версию прочитать не удалось», а не «безопасно»: тот же код 1 в --security, но в таблице он выглядит безобидно.

FAQ

Что именно исправлено в 8.1.0?

Это выпуск под CVE-2026-119977: добавлены проверка уязвимых ядер (--security), закрытие каталога обновлений (--harden), колонка CVE в --health, а режимы обновления теперь сообщают, если сайт остался ниже исправленной версии.

Можно ли звать --security каждую минуту?

Да, это режим только для чтения: ни блокировки, ни бэкапа он не берёт, поэтому безопасен для мониторинга и как проверка перед обновлением.

Почему --security вернул 3, а не 1?

Потому что 3 — ошибка окружения: не найден wp. Код 1 означает, что найден уязвимый или нечитаемый сайт. Различать их нужно в самом мониторинге, иначе тревога будет ложной.

Нужен ли --harden, если сайт за nginx?

Да, но применять надо не .htaccess, а напечатанную директиву: location ^~ /wp-content/upgrade/ { deny all; }.

Что изменилось в лицензии?

Проект перешёл на MIT: коммерческое использование больше не требует отдельного соглашения. Тексты прежней лицензии остались в архиве legacy/.

Чем отличается 8.1.1?

Только тестами: исправлен рекордер вызовов, который при параллельном прогоне терял записи. Ни режимы, ни опции, ни коды выхода не менялись.

Итог

8.1.0 — редкий случай, когда релиз про безопасность не добавляет «ещё одну защиту», а закрывает разрыв между «команда отработала» и «сайт действительно обновлён». Полезнее всего здесь два режима чтения: --security для мониторинга и колонка CVE в --health для инвентаризации, плюс --harden для тех, кто на Apache и LiteSpeed. Главная практическая ловушка — коды выхода: 1 и 3 означают совершенно разные вещи, и в моих замерах без WP-CLI обе команды дали именно 3.

Цитата: Успешное обновление — это не код возврата команды, а версия ядра на сайте после неё.

Связанные материалы

LLM Summary

  • Тема: Bash WP-CLI Update 8.1.0 — security-релиз скрипта обслуживания парка WordPress: проверка уязвимых ядер, закрытие каталога обновлений, MIT.
  • Уязвимость: CVE-2026-119977, состояние гонки в штатном обновляторе ядра, CVSS 8.1, в CISA KEV с 03.11.2026; затронуты 4.7–7.1.3, исправлены 7.1.4, 7.0.8, 6.9.11, 4.7.39, для 4.6 и старше исправления нет.
  • Новые режимы: --security (только чтение, вердикт по сайту, код 1 при уязвимом или нечитаемом сайте, код 0 если все безопасны) и --harden (маркированный блок в .htaccess, копия .htaccess.wp-cli-update.bak, директива для nginx печатается).
  • Конфигурация: --harden-upgrade-dir / --no-harden-upgrade-dir, ключ HARDEN_UPGRADE_DIR (по умолчанию 0); в --security, --health и --check флаг отвергается с кодом 2.
  • Отчёты: колонка CVE в --health (safe / UPDATE / ?) и поле cve_2026_119977 в JSON Lines.
  • Замеры 08.11.2026: SHA-256 архива совпал с SHA256SUMS (0d9b268b…58ba), архив 183 080 байт, bash -n чисто, --help печатает 8.1.0; без WP-CLI --check и --security возвращают 3.
  • Лицензия: MIT; тексты прежней лицензии остались в legacy/.
  • 8.1.1: только тесты — исправлен рекордер вызовов, терявший записи при -j 5.
  • Не проверялось: реальное обновление сайтов и работа --harden на живом Apache — сайтов и веб-сервера под рукой не было.
  • Ссылки: https://github.com/paulmann/Bash_WP-CLI_Update/releases/tag/v8.1.0, https://sysadministrator.ru/bash-wp-cli-update/

Промт для агента (установка и настройка)

Готовый промт для AI-агента: скопируйте блок целиком. Шаги собраны по AGENTS.md репозитория (две непререкаемых правила, порядок проверки) и по выводу --help версии 8.1.0.

Задача: обновить Bash WP-CLI Update до 8.1.0 и проверить, есть ли на хосте сайты, уязвимые по CVE-2026-119977.

Материалы:
- репозиторий: https://github.com/paulmann/Bash_WP-CLI_Update
- контракт для агентов: https://github.com/paulmann/Bash_WP-CLI_Update/blob/main/AGENTS.md
- релиз: https://github.com/paulmann/Bash_WP-CLI_Update/releases/tag/v8.1.0

Шаг 1. Скачать архив релиза и сверить контрольную сумму:
gh release download v8.1.0 -R paulmann/Bash_WP-CLI_Update -D ./rel
cd ./rel && sha256sum -c SHA256SUMS

Шаг 2. Распаковать поверх прежней копии, проверить синтаксис и версию:
bash -n Bash_WP-CLI_Update.sh
bash Bash_WP-CLI_Update.sh --help     # первая строка должна содержать 8.1.0

Шаг 3. Проверить окружение: bash Bash_WP-CLI_Update.sh --check
# код 0 — окружение в порядке; код 3 — нет wp или неверный WP_CLI_PATH

Шаг 4. Найти уязвимые сайты: bash Bash_WP-CLI_Update.sh --security
# код 0 — все на исправленной версии; код 1 — есть сайт ниже исправленной или версия не читается

Шаг 5. Обновить ядро и схему: --core (или --full), затем повторить --security до кода 0.
Шаг 6. Закрыть каталог обновлений: --harden, для nginx применить напечатанную директиву location ^~ /wp-content/upgrade/ { deny all; }
Шаг 7. Проверить инвентаризацию: --health, колонка CVE не должна показывать UPDATE или ?.

Запрещено:
- считать код 3 признаком уязвимости: это ошибка окружения, а не состояние сайта;
- ждать от --security лечения: он только читает и ничего не меняет;
- включать HARDEN_UPGRADE_DIR в режимах --security, --health, --check: флаг отвергается с кодом 2;
- оставлять сайты на ядрах 4.6 и старше в расчёте на исправление: его не будет;
- считать, что --harden работает на nginx: там нужна директива в конфиге сайта.

Что считать успехом: --check даёт 0, --security даёт 0, --health показывает safe по всем сайтам, каталог обновлений закрыт на уровне веб-сервера.