On October 21, 2026 the PHP team posted a security advisory called Critical remote code execution vulnerabilities, update now. That’s not a title you see on php.net very often.
The short version: two bugs, and both let an attacker run code on your server without logging in. PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 fix them. If you can update, go do that first and come back later.
I couldn’t update that night. Here’s what the bugs are and what I did instead.
The two bugs, in plain words
CVE-2026-109618: running out of memory at the wrong moment
When PHP runs out of memory, it stops the request and jumps straight to cleanup. The problem is timing. There’s a short moment where PHP has set aside memory for the request but hasn’t finished filling it in. If PHP runs out of memory right then, the cleanup code finds that half-built memory and trusts it.
An attacker can push a request into that moment with a crafted form upload. The request can stay under post_max_size and still use a lot of memory inside PHP.
Apache with mod_php is the confirmed case. There, the attack works before your application code even runs. PHP-FPM, which is what I use, is probably affected too, but nobody has shown a working exploit on it yet.
Details: GHSA-w8hw-w9fx-j79w
CVE-2026-109619: leftovers from the previous request
A PHP worker handles one request after another. Sometimes a request dies halfway (a fatal error, a timeout, out of memory) and leaves behind a pointer to memory that has already been freed. The next request on the same worker can pick up that pointer and use it.
Two PHP features were confirmed to pick up those leftovers:
- Session upload progress. It’s on by default, and it runs even if your app never starts a session.
- Fatal error backtraces. This one is new in PHP 8.5.
This bug was shown to work on PHP-FPM. I run PHP 8.5 on FPM, so this is the one I cared about most.
Details: GHSA-6wmf-4rv5-p3rp
Why I couldn’t just update
This blog runs in Docker, on top of the official WordPress images:
FROM wordpress:7.1.3-php8.5-fpm-alpine AS base
# ...
FROM wordpress:cli-php8.5 AS cli
PHP 8.5.12 was on php.net the same day, but these images still had 8.5.11. The Docker maintainers hadn’t rebuilt them yet. Short of compiling PHP myself, there was nothing I could change in my Dockerfile to get 8.5.12 that night.
The advisory has a section for people in my spot: “If you cannot update immediately.” It’s honest about it. These settings don’t make you safe. They close the attack paths the PHP team knows about. For one night, that was good enough for me.
The stopgap
I changed four settings:
; docker/php/php.ini
memory_limit = 256M
-post_max_size = 64M
-upload_max_filesize = 64M
+post_max_size = 32M
+upload_max_filesize = 30M
session.use_strict_mode = 1
+session.upload_progress.enabled = 0
error_log = /proc/self/fd/2
+fatal_error_backtraces = 0
# docker/nginx/default.conf
-client_max_body_size 64M;
+client_max_body_size 32M;
What each one does:
- Upload progress off. WordPress doesn’t use PHP sessions, so I lose nothing. Set this in
php.inior the FPM pool.ini_set()and.user.iniapply too late to help. - Fatal error backtraces off. My error logs get a little less detail for one night. Fine.
- Upload limit down from 64M to 32M. That’s the advisory’s number for sites that need uploads, with the file limit kept a bit below it. Nothing in my media library is close to 30M.
- nginx caps request bodies at 32M too. Oversized uploads get rejected before they reach PHP, including the ones that don’t say how big they are up front.
One suggestion I skipped: the advisory also mentions memory_limit = -1, which means no memory limit at all. On October 14 that 256M limit stopped a runaway process that tried to grab 4 GiB. I wasn’t going to remove a guard that had just done its job, for a bug nobody has exploited on FPM yet.
Merging to main doesn’t deploy this blog. I have to tag a release. So the stopgap went out as v0.12.2 that evening. I pulled the built images and checked the settings were in place. PHP was still 8.5.11, as expected.
The next morning: the real fix
The official images had been rebuilt overnight:
$ docker run --rm wordpress:7.1.3-php8.5-fpm-alpine php -v
PHP 8.5.12 (cli) (built: Oct 21 2026 15:57:41) (NTS)
$ docker run --rm wordpress:cli-php8.5 php -v
PHP 8.5.12 (cli) (built: Oct 21 2026 15:54:49) (NTS)
My Dockerfile uses a tag that follows the latest PHP 8.5 patch, so I didn’t have to edit it. I pulled the new base images, rebuilt, and checked that both containers reported 8.5.12.
Then I took the stopgap back out. Upload limits back to 64M, upload progress and backtraces back on. Those settings were only there to cover the gap. That went out as v0.12.3.
About 13 hours from advisory to patched PHP in production.
If you run PHP
- Update to 8.5.12, 8.4.27, 8.3.36 or 8.2.35. The PHP team is clear that nothing else fully fixes this.
- On Docker? Pull your base image again and rebuild. A tag that follows the latest patch does nothing until you pull it.
- On PHP 8.1 or older? The PHP project no longer ships updates for it. They did publish small source patches for 7.4, 8.0 and 8.1 this time, but your best bet is your Linux distribution or LTS vendor.
- Have to wait? Put the advisory’s settings in
php.inior the FPM pool, restart PHP, and leave yourself a note to remove them once you’ve updated. That note is the only reason I remembered to revert mine the next morning.
Sources
- Security advisory: Critical remote code execution vulnerabilities, update now (php.net, October 21, 2026)
- PHP 8.5.12 Released! and the 8.5.12 ChangeLog
- GHSA-w8hw-w9fx-j79w: RCE via OOM corruption (CVE-2026-109618)
- GHSA-6wmf-4rv5-p3rp: RCE via stale global state (CVE-2026-109619)
