Devops · PHP Development Notes · Tech News

PHP’s October 2026 Critical Security Release: What Changed, Who Is Affected and How to Patch

PHP critical security update, October 2026: PHP logo with a warning sign and a shield with a padlock

On 21 October 2026 the PHP project shipped PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 to fix two vulnerabilities rated critical, both of which can lead to remote code execution without any login. If you run PHP on a server that faces the internet, update today, and if you cannot update today, change the settings described below until you can.

I patched my own servers the same afternoon. This article is what I checked, in the order I checked it: what was fixed, who is really exposed, how to update on the common platforms, and what to change in the meantime. It deliberately contains no exploitation details; the official advisories are linked at the end for anyone who needs the full technical write-up.

What was fixed

Two separate flaws in the PHP engine were fixed in the same release, and both are rated critical by the PHP project. The changelog lists them under one line, “Avoid state corruption via bailout”, because they share a root cause: PHP abandoning an operation part way through and leaving memory in a state it should never reach.

Advisory CVE What goes wrong Confirmed impact
GHSA-w8hw-w9fx-j79w, “RCE via OOM corruption” CVE-2026-109618 When a request runs out of memory at a particular moment, PHP stops before request memory is fully set up, and the cleanup that follows acts on that half-initialized memory. Unauthenticated remote code execution as the web server’s PHP user
GHSA-6wmf-4rv5-p3rp, “RCE via stale global state” CVE-2026-109619 Some state that belongs to one request survives after that request’s memory is freed, and the next request handled by the same worker can touch it before PHP resets it (a use after free). Unauthenticated memory disclosure and remote code execution

Every release before the fixed versions is affected on all four supported branches. The fixed versions are 8.5.12, 8.4.27, 8.3.36 and 8.2.35, at the time of writing.

Am I affected?

You are affected if you run any PHP version older than the fixed releases, and how exposed you are depends mainly on how PHP is attached to your web server. The advisories are unusually clear about this, and it is the most useful thing to know before deciding how urgent your night is.

How PHP runs Exposure according to the advisories
Apache with mod_php Highest. Remote code execution was confirmed, in the worst case before any of your application code runs.
PHP-FPM (behind nginx, Apache mod_proxy_fcgi, Caddy) Conditional. One path was validated against FPM and depends on what the application does; the other is supported by source analysis without a complete demonstrated exploit.
FrankenPHP Likely susceptible, by analogy with mod_php.
LiteSpeed LSAPI Conditional, modeled on FPM.
Command-line scripts and cron jobs Not reachable from the network directly, but update them with everything else.

“Conditional” is not “safe”. The official position for both flaws is that updating is the only complete mitigation. PHP 8.1 and older are end of life and will not receive a fix; if you are still on one of them, this release is the reason to schedule the upgrade you have been postponing.

To see what you are running, check each way PHP is used on the machine, because the command-line version and the web version are often different:

php -v
php-fpm8.3 -v      # adjust to your version, one line per installed FPM
php -i | grep -E "Server API|memory_limit"
apachectl -M 2>/dev/null | grep -i php    # lists php_module if mod_php is loaded

One trap on Ubuntu: Ubuntu’s own packages keep the original upstream number and add security fixes as patches, so a fully patched Ubuntu PHP 8.3 still reports itself as 8.3.6. On those systems the version number tells you nothing. Read the package changelog instead (apt changelog php8.3-fpm) and look for the two CVE numbers.

How to update

The fix is a normal patch release, so updating is a routine package upgrade followed by a restart of every PHP process. The restart is the step people forget: an upgraded package on disk does nothing for a worker that loaded the old code yesterday.

Ubuntu with Ondřej Surý’s PPA, or Debian with DEB.SURY.ORG

Most servers that run PHP 8.4 or 8.5 on Ubuntu get it from this repository, which published the fixed builds on the same day.

sudo apt update
sudo apt install --only-upgrade 'php8.4-*'      # repeat for each branch you have
sudo systemctl restart php8.4-fpm
php8.4 -v

On release day the repository was overloaded and kept answering with HTTP 503 errors, so a plain upgrade failed half way. What worked for me was to separate the download from the installation: fetch the packages into the local cache first, retrying until every file arrives, then install from the cache without touching the network.

until sudo apt-get install -y --download-only 'php8.4-*'; do sleep 60; done
sudo apt-get install -y --no-download 'php8.4-*'

Note that unattended-upgrades on Ubuntu only installs from Ubuntu’s own origins by default, so packages from this repository are never updated automatically unless you add it to the allowed origins yourself.

Ubuntu’s own PHP packages

If you use the PHP that ships with Ubuntu (8.3 on 24.04, 8.1 on 22.04), the fix arrives as an Ubuntu security notice. At the time of writing Ubuntu rates both CVEs as critical, but the patched packages had not yet reached 24.04. Check the Ubuntu CVE tracker pages for the two CVEs, and once the update appears, sudo apt upgrade or unattended-upgrades will install it. Until then, apply the mitigations in the next section.

Debian

Debian 12 (bookworm) already has the fixed 8.2.35 in bookworm-security at the time of writing, so sudo apt update && sudo apt upgrade followed by a PHP restart is enough. Debian 13 (trixie) was still listed as vulnerable when I checked; follow the Debian security tracker and mitigate until it moves.

RHEL, AlmaLinux and Rocky with the Remi repository

Remi’s repositories usually follow upstream releases within days. sudo dnf upgrade 'php*' pulls the new build for the PHP module stream you have enabled, after which you restart php-fpm and, for mod_php, httpd.

Docker

Restarting a container does not update anything; you have to rebuild on the new base image and redeploy. Rebuild with docker build --pull so the floating tags such as php:8.4-fpm resolve to the new patch release, or pin the exact new version in your Dockerfile so the build is repeatable. Then confirm inside the running container with php -v.

Shared and managed hosting

On cPanel, Plesk, Laravel Forge, Ploi and similar platforms, the PHP version is usually chosen from a menu, but the patch level is decided by the provider. Check which exact version your sites report, and if it is not one of the fixed releases, ask your provider when it will be. If you control the site’s PHP settings, apply the mitigations below while you wait.

If you cannot update yet

Settings changes reduce the risk but do not remove it; both advisories say there is no complete configuration-only mitigation. Set these administratively, in php.ini or with php_admin_value and php_admin_flag in the FPM pool, so an application cannot override them, and restart every worker afterwards. In order of value for effort:

  1. Turn off session upload progress with session.upload_progress.enabled=0. It is enabled by default, almost nobody uses it, and it is part of one of the confirmed paths. I would leave it off even after patching.
  2. On PHP 8.5, turn off fatal error backtraces with fatal_error_backtraces=0. This setting is on by default in 8.5 and is involved in the strongest confirmed case.
  3. Consider memory_limit=-1, with care. The first advisory names this as the main configuration mitigation because it removes the predictable out-of-memory point. It also removes PHP’s own protection against a runaway script, so put a memory limit around each worker at the operating system or container level instead. The advisory specifically warns not to use RLIMIT_AS or RLIMIT_DATA for this, because they make the vulnerable path more likely, not less.
  4. Move from mod_php to PHP-FPM if you can. FPM is the less exposed of the two in both advisories, and it is the better setup anyway.
  5. Tighten request limits in front of PHP. Keep post_max_size conservative and enforce a request body limit at the web server, firewall or CDN as well. Lower max_input_nesting_level, keep max_input_vars and max_file_uploads modest, and block multipart form uploads at the front on sites that never accept them.
  6. Remove per-request PHP setting overrides. Settings passed per request (php_value in .htaccess with mod_php, or PHP_VALUE sent from nginx or Apache to FPM) and obsolete directives that produce deprecation warnings are part of the second advisory. Move what you need into php.ini or the pool configuration and delete the rest.
  7. Fix the fatal errors and timeouts you already see. Fatal errors, failed includes and “Maximum execution time exceeded” on pages anyone can reach are the interruptions both flaws depend on. Your error log is the to-do list.
  8. As a last resort on small sites, set pm.max_requests=1 in the FPM pool so each worker handles a single request. It costs performance, but it removes the “next request on the same worker” condition.

For an FPM pool, the first two items look like this:

; /etc/php/8.5/fpm/pool.d/www.conf
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[fatal_error_backtraces] = 0

How to check you are done

You are done when every PHP process that can serve a request reports a fixed version and has been restarted since the upgrade. My checklist:

  • Each installed PHP branch reports 8.5.12, 8.4.27, 8.3.36 or 8.2.35 or later (or, on Ubuntu’s own packages, a changelog that names both CVEs).
  • Every FPM service and, for mod_php, Apache itself has been restarted after the upgrade.
  • No forgotten pool is still running an old version. Old PHP versions that you no longer use should be stopped and disabled, not left running in the background.
  • Containers have been rebuilt and redeployed, not just restarted.
  • The PHP and web server error logs look normal after a few hours, and the mitigations you want to keep (upload progress off, at least) are still in place.

What I take from this

The fix itself was routine; what made the day busy was everything around it. Three things I would put in place before the next one rather than after it. First, stay on a supported PHP branch, because a release like this one is exactly what the “security support until” date on php.net is for. Second, automate patching for every repository your servers use, including third-party ones that the default update tooling ignores, and know in advance how you will restart workers safely. Third, prefer PHP-FPM over mod_php, and keep per-request configuration out of your web server setup. None of this is new advice, but releases like this one are when it pays off.

Next steps

If you build on Laravel, two related pieces on this site go further into application-level security: Laravel Security in Times of AI Code Generation and Preventing the OWASP Top 10 in Laravel. If you would like a second pair of eyes on how your PHP estate is patched and configured, that is part of my consultancy work, and you can reach me here.

References