
🌐 Also available in: Deutsch · Français · Español
On 21 October 2026 the PHP project shipped four releases at once – 8.5.12, 8.4.27, 8.3.36 and 8.2.35 – and the release notes skipped the usual “bug fix release” small talk. Two critical vulnerabilities, CVSS 9.2 each, unauthenticated remote code execution, and one sentence that every admin should read twice: “There are no complete mitigations, updating is the only safe choice.”
The bugs have been in PHP for a very long time; the interesting part is not a single bad line of code but how PHP cleans up after itself. Here is the short, nerdy version.
🧨 Bug 1: the out-of-memory parachute that opens too early
CVE-2026-109618. When a request runs out of memory, PHP does not unwind politely – it jumps straight out with longjmp(). If that happens while request data is only half initialised, the cleanup at the end of the request treats the half-built structures as valid and works on garbage. With the right garbage, that is code execution as the web server user.
The nasty bit: you can reach out-of-memory while staying inside the limits PHP thinks it enforces. Multipart uploads without a usable length slip past post_max_size, multipart parts may carry unlimited headers that cost far more memory inside PHP than on the wire, and empty file fields do not count towards max_file_uploads. The fix removes longjmp() for out-of-memory entirely.
👻 Bug 2: state from the last request haunts the next one
CVE-2026-109619. A PHP worker serves many requests in a row. Some global state – errors, sessions, extension data – can still point into the memory of the previous request after that memory has been freed. If the next request touches that state before PHP has reset it, you get a classic use-after-free. Confirmed triggers: the fatal-error backtraces new in PHP 8.5, and the session upload progress feature.
🎯 Who is affected
- Everything that serves web requests: PHP-FPM, Apache with
mod_php(exploit confirmed, highest risk), php-cgi, FrankenPHP, LiteSpeed. - For PHP-FPM the session upload progress path was validated as RCE; the out-of-memory path is “susceptible by source analysis”.
- Branches 8.2 to 8.5. PHP 8.1 and older get no fix at all – if you still run it, this is your sign. PHP 8.2 itself reaches end of life on 31 December 2026.
🩹 Stop-gaps if you really cannot update today
session.upload_progress.enabled = 0(and keep it off afterwards if you do not use it), plusfatal_error_backtraces = 0on PHP 8.5 – restart all workers.- Limit request bodies, multipart parts and headers at the reverse proxy; block multipart entirely where the application does not need uploads.
- A container or cgroup memory limit – not
RLIMIT_AS/RLIMIT_DATA, those trigger exactly the vulnerable path. - All of these reduce risk. None of them closes the hole. The advisories say so themselves.
🐳 The container trap – the price of layers
Containers have a downside that a day like this makes painfully visible. An official image is not built in one piece; it is a stack of layers, and every layer belongs to someone else: a Debian base, on top of it the official php image, on top of that the wordpress or nextcloud image. A fix in PHP has to travel up that chain, one floor at a time:
- The PHP project publishes the release (here: 21 October, in the afternoon, European time).
- The maintainers of the official
phpimage update their build files, a reviewer merges them, and the build farm rebuilds every variant – fpm, apache, cli, alpine, debian, for every architecture. That happened about an hour after the release. - Only then can the
wordpressandnextcloudimages be rebuilt on top of the new base, again for every tag and every architecture – under the same tag as before. That step came hours later, not minutes. - And only then can my update run pull the new image and restart the pods.
With a classic server you would type apt upgrade as soon as your distribution ships the package – distributions get the patches in advance and usually publish within hours. With containers you cannot simply update PHP inside the image: the container is meant to be replaced, not patched, and anything you change by hand is gone at the next restart. You wait for the people who build the layers. Most of the time that is a feature – reproducible, tested images, an update is one image swap, a rollback is the previous tag. On a day with a critical RCE it is a waiting room.
Two practical consequences. First: the tag says nothing. wordpress:7.1.3-php8.4-fpm was the same tag before and after the fix, so check the PHP version inside the image: docker exec … php -v or kubectl exec … -- php -r "echo PHP_VERSION;" must say 8.4.27 / 8.5.12 (or 8.3.36 / 8.2.35) – then pull the image again and restart the pod. Second: have a plan for the waiting time. That is what the stop-gaps above are for.
🏠 And on my own servers?
Yes, affected – all three. The blog runs WordPress in the official wordpress:…-php8.4-fpm image, the two Nextcloud servers the official nextcloud:…-fpm image with PHP 8.5: PHP-FPM everywhere, behind nginx. And both confirmed paths were open: session upload progress is on by default, and on PHP 8.5 so are the fatal-error backtraces. The rest of the setup makes an attack harder – no mod_php, body size limits at the ingress, a memory limit on every pod, SELinux around every container – but harder is not impossible, and none of it is a fix.
The waiting time. The fixed PHP was out, the fixed images were not (see the container trap above). So for those hours I took the gentle route from the stop-gap list: session.upload_progress.enabled = Off on all three servers, and on the two Nextclouds with PHP 8.5 also fatal_error_backtraces = Off. That closes exactly the two paths the advisories confirmed as exploitable under PHP-FPM, and neither application uses either feature – WordPress does not use upload progress at all, Nextcloud uploads large files in chunks through JavaScript. The sites stayed online. It is not a fix: the out-of-memory path stays theoretically open until the patched PHP runs. Both settings stay off after the update, too: the advisory recommends keeping upload progress disabled where it is not needed – a feature nobody uses cannot open the next hole – and the fatal-error backtraces add little here, because Nextcloud writes its errors with a stack trace into its own log anyway.
Status: all clean. The rebuilt WordPress image with PHP 8.4.27 appeared at 20:06 CEST (18:06 UTC), about four hours after the PHP release; the rebuilt Nextcloud image with PHP 8.5.12 followed at 20:25 CEST (18:25 UTC). The blog runs the patched PHP since 20:26, the two Nextcloud servers since 20:31 and 20:36 CEST – checked inside every container, not by looking at the tag, together with the two stop-gap settings, which stay off. From the release to the last patched server: about four and a half hours, most of it spent waiting for the images. No traces of an attack in the logs, and the integrity checks of WordPress (core and all plugins) and Nextcloud came back clean. I am safe. 🐘✅
⏱️ TL;DR
Two critical, unauthenticated RCEs in PHP itself, every web SAPI, no real workaround. Update to 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 now – distribution packages, container images, hosting control panel, whatever you use. And if your hoster runs PHP for you: ask them today whether they have. apt upgrade was never more literal. 🐘🔐
No warranty: this post describes what I found and did on my own servers, to the best of my knowledge on the day of writing. I take no responsibility for your systems – neither for the update nor for the stop-gaps described here, which explicitly do not protect you completely. The only real fix is the patched PHP version; check the official advisories for your setup.
Sources: PHP security advisory, 21 Oct 2026, GHSA-w8hw-w9fx-j79w, GHSA-6wmf-4rv5-p3rp.





