PHP shipped an out-of-cycle security release on October 21, 2026 for two remote code execution bugs in the core runtime, now called PHP2Shell. The details leaked a day early, exploit attempts were logged before the patch existed, and a follow-up advisory on October 23 added a third CVE. If you run PHP behind a web server, this is a patch-and-restart job, not a configuration change.

What was fixed on October 21, 2026

The PHP team rates both advisories CVSS v4.0 9.2 (Critical); both allow unauthenticated code execution as the web worker account:

  • CVE-2026-109618, "RCE via OOM corruption" (GHSA-w8hw-w9fx-j79w). An out-of-memory error while request data is only partly initialized leaves half-built data that request cleanup treats as valid. A crafted multipart body can trigger it before any application code runs.
  • CVE-2026-109619, "RCE via stale global state" (GHSA-6wmf-4rv5-p3rp). Request-owned state can outlive the memory it points to, and a later request on the same worker reuses it before initialization resets it. PHP confirmed two paths: fatal error backtraces (PHP 8.5 only) and session upload progress, which is on by default and runs even if the application never calls session_start().
Branch Fixed release
8.5 8.5.12
8.4 8.4.27
8.3 8.3.36
8.2 8.2.35

PHP 8.1 and older get no release: PHP published minimal source backports for 7.4, 8.0 and 8.1, vendors are patching, and Google and AWS list 5.4 onward as affected. Every SAPI serving web requests is in scope: PHP-FPM, Apache mod_php, php-cgi, FrankenPHP and LiteSpeed. PHP rates mod_php the highest risk, but the upload-progress path was validated against FPM too.

How the week unfolded

  • October 17: Amazon Threat Intelligence logged an exploit attempt against its MadPot honeypots, four days before disclosure. Amazon says it is "unclear if any of these attempts would have succeeded in real-world systems."
  • October 20: A Hacker News post leaked both CVE IDs, a CVSS of 10.0 and an October 22 disclosure date. watchTowr confirmed the bugs were real, and that evening PHP pulled the release forward to October 21 at 14:00 UTC with the real score, 9.2.
  • October 21: Amazon saw multiple proof-of-concept exploits from around 02:00 UTC and Cloudflare's WAF rules went live at 03:02 UTC. The fixed releases and the Debian, Ubuntu, cPanel and Plesk packages landed the same day.
  • October 23: PHP published an informational advisory for CVE-2026-115560 (below).

Attempts are not in doubt: watchTowr, Cloudflare and Amazon saw them by October 21, and The Hacker News reported Cloudflare's count climbing from tens of thousands within 45 minutes of disclosure to millions by early October 22 (Cloudflare's post gives no figures). Confirmed compromises are thinner: Huntress saw none across its partner base as of the afternoon of October 21, and on October 25 Unit 42 retracted an earlier report, saying it was "unable to confirm that initial access is associated with the specific PHP2Shell CVEs." Assume attempts; verify intrusions.

Why session.upload_progress.enabled=0 is not enough

PHP's advisory lists this setting and says it "blocks the confirmed session paths but not other variants." Datadog Security Labs is blunter: mitigations circulating in the community "such as setting session.upload_progress.enabled=0 in the PHP configuration file, don't fully protect you." The reasons:

  • It only closes the upload-progress path of CVE-2026-109619. On PHP 8.5 the fatal-backtrace path needs fatal_error_backtraces=0 as well, and diagnostics raised by per-request INI settings (.htaccess, php_value, proxy PHP_VALUE) are a separate way in.
  • It does nothing for CVE-2026-109618. Its partial mitigations (memory_limit=-1 via php_admin_value, a low post_max_size, cgroup limits rather than RLIMIT_AS) are also incomplete: an underlying allocation failure can still reach the vulnerable path.
  • It has to go in php.ini, the FPM pool or the server config, with a restart of every worker; ini_set() and .user.ini apply too late.

PHP's release notes say it directly: "There are no complete mitigations, updating is the only safe choice."

CVE-2026-115560, the October 23 advisory

On October 23 PHP added a third CVE, also in session upload progress, that affects fully patched builds including 8.5.12. It stays in the regular release cycle because it needs an unusual setup: session.serialize_handler set to php_binary or php_serialize in configuration, switched to php at runtime with ini_set() before session_start(), with upload progress still enabled. PHP calls it "an unlikely RCE vector" and asks that you keep session.upload_progress.enabled=0 until the next bugfix release. No exploitation has been reported, and if your applications do not need upload progress, leave it disabled permanently.

What to do now

Patch order

  1. Internet-facing mod_php hosts first, then FPM, then anything internal.
  2. Distro packages: Debian 13 gets php8.4 8.4.27-1~deb13u1 (DSA-6574-1) and Debian 12 php8.2 8.2.35-1~deb12u1 (DLA-4848-1). Ubuntu USN-8948-1 covers 24.04 (php8.3 8.3.6-0ubuntu0.24.04.13), 22.04 (php8.1 8.1.2-1ubuntu2.28) and 26.04. Ubuntu's version strings stay at 8.3.6; the fix is backported.
  3. cPanel: EasyApache 4 25.91 fixes ea-php74 through ea-php85. cPanel & WHM 138.0.18, 136.0.50 and 134.0.66 carry PHP 8.4.27 for the panel's internal PHP.
  4. Plesk: The October 21, 2026 change log lists Plesk PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35, Linux backports for 8.1.34, 8.0.30 and 7.4.33, and Obsidian 18.0.81 Update 4 or 18.0.80 Update 11 for the panel engine.
  5. Docker: The official php image has 8.5.12, 8.4.27, 8.3.36 and 8.2.35 tags. Rebuild every image that bakes in PHP and redeploy; a new tag does nothing for a running container.
  6. EOL branches with no vendor: apply PHP's minimal source backports or move to 8.2 or newer, and plan past 8.2, which stops getting fixes on December 31, 2026.

Check what is actually running

The CLI binary and the serving binary can differ, and vendor backports keep the old version string, so check the changelog and the serving binary, not just php -v:

php -v
php-fpm8.3 -v                        # or /opt/cpanel/ea-php83/root/usr/bin/php -v
php -i | grep -E "Loaded Configuration|session.upload_progress.enabled|memory_limit|post_max_size"
apt-get changelog php8.3-fpm | grep -E "CVE-2026-10961[89]"
rpm -q --changelog php-fpm | grep -E "CVE-2026-109618|CVE-2026-109619"

Check each FPM pool too (a pool's php_admin_value overrides php.ini) and every installed PHP version, not just the default.

Restart and verify

A package upgrade does not touch workers that still have the old libphp.so or php-fpm loaded. Restart every SAPI explicitly and check worker start times:

systemctl restart php8.3-fpm apache2    # or httpd, frankenphp, lsws
ps -o pid,lstart,cmd -C php-fpm8.3

If a host shows signs of probing, capture worker memory before restarting; the restart destroys the evidence.

Edge rules as a stopgap

Cloudflare, AWS WAF and Google Cloud Armor all shipped rules. On your own proxy, block multipart/form-data on routes without uploads, cap request bodies (nginx client_max_body_size 8m;), reject chunked POSTs, and drop PHPSESSID cookies not matching ^[A-Za-z0-9,-]{22,256}$. Know the limits: AWS says a WAF cannot address fatal_error_backtraces or server-side INI diagnostics, and Cloudflare's rule does not cover sites that changed session.upload_progress.name. They buy time to patch; they are not a plan.

What to look for in logs

  • PHP error log: Allowed memory size of ... exhausted ... in Unknown on line 0. "Unknown on line 0" means the failure hit during request initialization. Datadog notes a complete attack "can produce as few as two to four memory exhaustion errors and then go quiet."
  • Apache: AH00052: child pid ... exit signal Segmentation fault (11).
  • Requests: POST bodies containing PHP_SESSION_UPLOAD_PROGRESS (Amazon's primary indicator), multipart bodies with hundreds of parts or names like files[R00001][a][a][a].
  • Responses: Set-Cookie: PHPSESSID= values longer than 256 bytes or percent-encoded binary, which points to memory disclosure.
  • Processes: php-fpm, httpd, apache2 or frankenphp spawning sh, bash, curl, wget or nc. The strongest signal; it can happen with no crash and no error-log entry.

Search back to at least October 17, 2026, not October 21.

Sources