21 октября 2026 года команда PHP выпустила внеплановые релизы 8.5.12, 8.4.27, 8.3.36 и 8.2.35. Они закрывают две критические уязвимости в ядре, каждая с оценкой 9.2 по CVSS v4.0. В обеих подтверждено удалённое выполнение кода без авторизации, причём для одной из них — ещё до того, как управление дойдёт до кода вашего приложения.

Релиз планировали на 17:00 МСК, но бюллетени появились около 16:30: подробности утекли раньше эмбарго. Ниже — разбор официальных бюллетеней без пересказа слухов, скрипт для проверки сервера и временные меры для тех, кто не может обновиться прямо сейчас.

Коротко

CVE-2026-109618

CVE-2026-109619

Бюллетень

GHSA-w8hw-w9fx-j79w

GHSA-6wmf-4rv5-p3rp

Суть

RCE через порчу состояния при нехватке памяти (OOM)

RCE через use-after-free «протухшего» глобального состояния воркера

CVSS v4.0

9.2 (AV:N/AC:H/AT:P/PR:N/UI:N)

9.2 (AV:N/AC:H/AT:P/PR:N/UI:N)

Авторизация

не нужна

не нужна

Подтверждённая RCE

Apache mod_php

Apache mod_php; сценарий с сессиями — также PHP-FPM

Исправлено в

8.2.35, 8.3.36, 8.4.27, 8.5.12

8.2.35, 8.3.36, 8.4.27, 8.5.12

Все ветки до 8.1 включительно официально не поддерживаются, и исправлений для них от PHP не будет.

Что именно сломано

CVE-2026-109618: OOM и longjmp()

Когда скрипту не хватает памяти (memory_limit), PHP прерывает обработку запроса через longjmp(). Проблема в том, что в некоторых местах память запроса уже доступна, но ещё не инициализирована. Если любое выделение памяти падает в этот момент, процедура завершения запроса потом работает с невалидными данными. Это и превращается в RCE.

Самое неприятное — способы гарантированно довести запрос до OOM, не выходя за видимые лимиты. Все они связаны с разбором multipart/form-data:

  • multipart-запрос без корректной длины тела может пройти проверку post_max_size и продолжать слать данные;

  • у части multipart может быть неограниченное количество заголовков, а в памяти PHP они занимают гораздо больше, чем по сети;

  • пустые поля загрузки файлов не считаются в max_file_uploads, но создают массивы метаданных, а вложенные имена полей умножают эту работу.

Почему mod_php страдает сильнее всего: Apache с mod_php вызывает завершение запроса, даже если старт запроса упал. Разбор тела происходит ещё до вашего кода, поэтому атака не зависит от приложения: у вас может быть хоть пустой index.php. По данным бюллетеня, полная RCE подтверждена против mod_php с лимитами PHP по умолчанию. FrankenPHP, по анализу исходников, ведёт себя так же. PHP-FPM в этом сценарии просто убивает воркер, но после нормального старта OOM всё ещё опасен: FPM считается уязвимым, хотя полного эксплойта под него не показали.

CVE-2026-109619: «протухшее» состояние между запросами

Воркер PHP хранит глобальное состояние: ошибки, сессии, объекты, состояние расширений. Иногда оно указывает на память конкретного запроса. Если запрос прервался фатальной ошибкой (в том числе из-за той же нехватки памяти или таймаута), сброс этого состояния может не произойти. Память запроса освобождается, а указатель остаётся. Следующий запрос в том же воркере обращается к нему раньше нормальной инициализации — получается use-after-free.

Для атаки нужны два запроса: один оставляет мусор, второй его использует. Несколько воркеров снижают шанс попасть в тот же процесс, но не устраняют проблему. Подтверждено:

  • RCE через путь с fatal error backtraces (PHP 8.5) против mod_php;

  • RCE через жизненный цикл сессий против mod_php и PHP-FPM;

  • утечка памяти процесса.

Проверяем сервер за минуту

Один бинарник

php -v

Безопасные версии: 8.2.35+, 8.3.36+, 8.4.27+, 8.5.12+.

Но php -v в консоли часто показывает не ту версию, которая обслуживает сайт. На серверах с ISPmanager, cPanel, CloudLinux или Remi стоит по несколько PHP, а сайт может работать через php-fpm другой версии.

Все PHP на машине

Скрипт ищет PHP в типичных местах (системные пакеты, Remi, cPanel EA, CloudLinux alt-php, ручные сборки) и сравнивает каждую версию с исправленной:

#!/usr/bin/env bash
# Ищет PHP на сервере и сравнивает версии с исправленными (PHP2Shell, 21.10.2026)
fixed() { case "$1" in 8.2) echo 35;; 8.3) echo 36;; 8.4) echo 27;; 8.5) echo 12;; esac; }

for bin in /usr/bin/php* /usr/sbin/php-fpm* /usr/local/bin/php* /usr/local/sbin/php-fpm* \
           /opt/remi/php*/root/usr/bin/php /opt/remi/php*/root/usr/sbin/php-fpm \
           /opt/cpanel/ea-php*/root/usr/bin/php /opt/alt/php*/usr/bin/php \
           /opt/php*/bin/php /usr/local/php*/bin/php; do
  [ -x "$bin" ] && [ -f "$bin" ] || continue
  case "$(basename "$bin")" in phpize*|php-config*) continue;; esac
  v=$("$bin" -v 2>/dev/null | head -n1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
  [ -n "$v" ] || continue
  branch=${v%.*}; patch=${v##*.}; need=$(fixed "$branch")
  if [ -z "$need" ]; then
    case "$branch" in 8.[6-9]) status="тестовая ветка, проверьте вручную";;
                      *) status="EOL: исправления от PHP не будет";; esac
  elif [ "$patch" -ge "$need" ]; then status="OK"
  else status="УЯЗВИМ: нужна $branch.$need или новее"; fi
  printf '%-45s %-8s %s\n' "$bin" "$v" "$status"
done

Пример вывода:

/usr/bin/php7.4                               7.4.33   EOL: исправления от PHP не будет
/usr/sbin/php-fpm8.4                          8.4.26   УЯЗВИМ: нужна 8.4.27 или новее
/opt/remi/php85/root/usr/bin/php              8.5.12   OK

⚠️ Важно про пакеты дистрибутивов. Debian, Ubuntu, RHEL и другие часто переносят исправления в старую версию, не меняя её номер. Скрипт покажет «уязвим», хотя пакет уже залатан. В таком случае смотрите changelog пакета (apt changelog php8.2-fpm, rpm -q --changelog php-fpm | head) и трекер безопасности своего дистрибутива по номерам CVE. И наоборот: ветки 7.x и 8.0/8.1 из сторонних репозиториев вряд ли получат исправление вообще.

Docker

docker ps --format '{{.Names}}' | while read c; do
  printf '%-30s ' "$c"; docker exec "$c" php -v 2>/dev/null | head -n1 || echo "php не найден"
done

Не забудьте пересобрать образы, а не только перезапустить контейнеры: в базовом образе php:8.x должна оказаться исправленная версия.

Если доступа к консоли нет

  • WordPress: «Инструменты» → «Здоровье сайта» → «Информация» → «Сервер».

  • 1С-Битрикс: «Настройки» → «Инструменты» → «Проверка системы».

  • Виртуальный хостинг: версия обычно видна в панели. Обновление PHP — задача хостера, напишите в поддержку и уточните сроки.

  • Заголовок X-Powered-By (curl -sI https://example.com | grep -i powered) — ненадёжно: его часто скрывают, а версия в нём может не совпадать с реальной.

Обновляемся

После обновления пакетов обязательно перезапустите все воркеры (php-fpm, Apache), иначе в памяти продолжит работать старый код:

# Debian/Ubuntu, пример для 8.3 из ondrej/php
apt update && apt install --only-upgrade 'php8.3*'
systemctl restart php8.3-fpm   # или apache2 для mod_php

# RHEL/Alma/Rocky с Remi
dnf upgrade 'php*'
systemctl restart php-fpm

Затем снова прогоните скрипт или php -v и проверьте сайт.

Если обновиться прямо сейчас нельзя

Оба бюллетеня прямо пишут: полноценная защита — только обновление. Всё ниже лишь сужает поверхность атаки, пока вы готовите обновление.

Против CVE-2026-109618 (OOM):

  • Принудительный memory_limit=-1 на уровне администратора (php_admin_value в пуле FPM или конфиге Apache) с перезапуском всех воркеров. Это убирает предсказуемый лимит, на котором построен эксплойт. Но сервер теряет защиту от прожорливых скриптов, поэтому ограничивайте память снаружи (cgroup/контейнер) и следите за нагрузкой.

  • Не используйте RLIMIT_AS/RLIMIT_DATA как замену: по бюллетеню это как раз переводит PHP в уязвимую ветку.

  • Держите консервативный post_max_size, уменьшите max_input_nesting_level и max_input_vars, ограничьте размер тела и количество частей multipart на фронтенде (nginx, WAF).

  • Если сайт не принимает multipart/form-data (нет загрузки файлов и форм с файлами), режьте такие запросы на фронтенде.

Против CVE-2026-109619 (stale state):

  • На PHP 8.5: fatal_error_backtraces=0 на уровне администратора — убирает подтверждённый путь к RCE.

  • session.upload_progress.enabled=0 — закрывает подтверждённый сценарий с сессиями. Авторы бюллетеня советуют выключить его и после обновления, если функция не нужна.

  • Если производительность не критична — pm.max_requests=1 в пуле FPM: каждый воркер обрабатывает один запрос, и «мусору» не к кому перейти.

  • Ищите и устраняйте фатальные ошибки и предупреждения, которые атакующий может вызвать запросом: загрузки, импорты, страницы ошибок, деструкторы, обработчики вывода.

Что делать владельцам сайтов на PHP 7.x и 8.0/8.1

Это самая болезненная часть. В рунете огромное количество сайтов на Битриксе, WordPress и самописных движках со старым PHP. Исправлений для этих веток не будет, а временные меры выше не дают полной защиты.

Реальный выход один — переезд на поддерживаемую ветку (8.2+). Это не всегда «поменять версию в панели»: старые модули, плагины и самописный код могут сломаться. Поэтому порядок такой:

  1. Сделать полный бэкап сайта и базы.

  2. Развернуть копию на новой версии PHP и прогнать основные сценарии: каталог, корзина, оплата, формы, админка.

  3. Исправить несовместимости (обычно это устаревшие функции, each(), create_function(), строгие типы, изменения в mysqli).

  4. Переключить боевой сайт и временно включить меры из раздела выше, пока переезд не завершён.

Чек-лист

  • [ ] Найти все PHP на сервере, а не только тот, что в php -v.

  • [ ] Обновить до 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 или проверить бэкпорт в пакете дистрибутива.

  • [ ] Перезапустить php-fpm и Apache.

  • [ ] Пересобрать Docker-образы.

  • [ ] Если обновиться нельзя — включить временные меры и запланировать обновление.

  • [ ] Если ветка 7.x / 8.0 / 8.1 — планировать переезд, а не ждать патча.

  • [ ] Проверить логи на всплески ошибок нехватки памяти и фатальных ошибок при разборе POST-запросов.

Источники


Если не хотите разбираться сами — могу помочь: проверю, какие версии PHP реально обслуживают ваши сайты, обновлю их или перенесу проект со старого PHP 7.x на актуальную ветку с проверкой работоспособности. Пишите в Telegram: @sonic_h1.

Комментарии (11)


  1. unsec
    21.10.2026 14:25

    https://php2shell.ru - методы зщаиты от PHP2Shell и ссылки на патчи, информация обновляется.


    1. trinxery
      21.10.2026 14:25

      Спамить плохо


      1. slbeat
        21.10.2026 14:25

        Зависть? Человек помощь сообществу хочет!


        1. trinxery
          21.10.2026 14:25

          Пусть придумает другой способ, все его комментарии это спам этой ссылкой. Если применять критерий полезности для общества, то окажется, что всем можно спамить чем угодно где угодно, а это, очевидно, вредно.

          P.S. Если оценивать текст сайта, то первый же рекомендуемый способ исправления уязвимости (не считая самого патча), судя по [1], на самом деле не работает. На сайте даже нет почты для обратной связи, поэтому @unsec никогда бы не узнал, если у него что-то написано не так.


          1. unsec
            21.10.2026 14:25

            На сайте агрегация способов защиты от уязвимости, никаких почт и ссылок нет - он сделан для оповещения об уязвимости и добавлен в посты про багу для удобства получения информации, извините если вас это задело. Замечания и исправления можно прислать мне в личные сообщения.


  1. dtmse
    21.10.2026 14:25

    Уязвимы ли совсем старые версии PHP? До сих пор есть сайты, которые работают на 5.X


    1. unsec
      21.10.2026 14:25

      да, уязвимы


    1. ValdikSS
      21.10.2026 14:25

      5.4 включительно



  1. evgeniymx
    21.10.2026 14:25

    Так ведь получается достаточно уменьшить на фронтенде макс размер файла до меньшего размера, чем указано в memory_limit/post_max_size/upload_max_filesize, чтобы еще на уровне nginx запрос обрывался с 413 (или apache c 400), и утечка памяти была бы невозможной, т.к. memory_limit бы и не дергался (это касается CVE-2026-109618)


    1. NotSlow
      21.10.2026 14:25

      Проблема еще в том, что memory_limit может быть задан в php.ini и потом еще 10 раз изменен в .htaccess и самих php скриптах. Причем как в большую, так и в меньшую сторону. Много раз наблюдал когда изначально стоит допустим 1024мб лимит, но скрипт обрывается с ошибкой по памяти. В итоге выясняется что где-то в недрах скриптов зачем-то стоит невозмутимая строчка типа ini_set(‘memory_limit’, '128M');

      А если в nginx сделать совсем уж малое значение, то появиться могут проблемы у нормальных запросов.