CVE-2026-109619: code execution through state left behind
Published · updated
The PHP release of 21 October 2026 carried two remote-code-execution fixes that are usually spoken of as one event. They are different bugs: CVE-2026-109618 corrupts memory inside a single request, CVE-2026-109619 abuses global state that survives into the next one. Both are unauthenticated, both are fixed by the same update, and only one of them needs more than a single request.
What the bug actually is
PHP normally resets its request state at the boundary between requests. CVE-2026-109619 is a path where that reset is incomplete: under specific multipart and session-upload conditions, a structure from the previous request is still reachable when the next one starts. An attacker who controls both requests can then shape the leftover state and have the interpreter act on it.
Two consequences follow, and they matter for how you reason about exposure:
- It is not a one-shot exploit. The advisory describes at least two related requests that must reach the same worker process. Under PHP-FPM with several pools or a load balancer, an attacker has to keep the connection on the same backend — harder, not impossible.
- It does not need your application. The affected code runs while PHP is setting the request up, before your framework, router or login check is entered. A WAF that inspects form fields and a login page that guards the admin area are both behind the point of execution.
Both CVE identifiers target every way of serving PHP: PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. The PHP team singles out mod_php as the most dangerous configuration, because the request is executed in the web server process itself.
Fixed builds
| Branch | Vulnerable | Fixed |
|---|---|---|
| PHP 8.5 | below 8.5.12 | 8.5.12 |
| PHP 8.4 | below 8.4.27 | 8.4.27 |
| PHP 8.3 | below 8.3.36 | 8.3.36 |
| PHP 8.2 | below 8.2.35 | 8.2.35 |
| PHP 8.1 and older | all builds | source backports only |
PHP published minimal source backports for 7.4, 8.0 and 8.1, which is a task for whoever maintains the server — those branches reached end of life and receive no packages. The supported replacement for an end-of-life branch is an upgrade, not a patch. PHP end-of-life dates →
What a passive check can and cannot tell you
There is no external test that proves this bug is present. Deciding whether a site is vulnerable means knowing its exact build, and the build is only public when it leaks: an X-Powered-By header, a reachable phpinfo(), a PHP-FPM status page. Everything else is inference dressed as a scan.
Which still leaves three useful things an outside check can do:
- read the version when it is published and compare it against the fixed builds;
- find the leaks that publish it for you — an open status page is both a version disclosure and a way to see request URIs and pool configuration;
- confirm which server API is in play, because mod_php changes how urgent the patch is.
If the version is hidden, the honest report says “not disclosed”. The proof is one command on the server: php -v, or php-fpm8.3 -v for the FPM binary the site is switched to.
What to do, in order
- Update PHP. To 8.2.35, 8.3.36, 8.4.27 or 8.5.12. Distribution packages and LTS vendors had the patches in advance, so updating through your package manager is the fast path.
- Restart the workers. An updated binary does nothing until the running FPM master reloads:
systemctl reload php8.3-fpm, or a panel restart. Long-lived workers keep the old code in memory. - If you cannot update today, reduce the blast radius. The advisory suggests removing the memory ceiling in the FPM pool and lowering
post_max_sizeto 8M (32M with uploads). Understand the trade:memory_limit = -1removes the guard against ordinary runaway scripts. - Do not treat “session.upload_progress off” as a fix. Early guidance mentioned it; independent researchers reported that it does not stop the attack. It is a partial measure at best.
- Look for evidence of use. Large multipart requests, memory-exhaustion errors at request start, unexpected shell processes, new files in upload directories. A successful exploit does not have to crash anything, so a quiet log proves nothing.
- Re-check and keep the timestamped result. If you run sites for clients, that report is the evidence they will ask for.
Sources
- GHSA-6wmf-4rv5-p3rp — CVE-2026-109619 advisory
- php.net — release announcements, 21 October 2026
- CERT-EU Security Advisory 2026-018
- NCSC-NL operational repository — detection notes and mitigations
- Datadog Security Labs — reproduction details
Questions
Is CVE-2026-109619 exploited in the wild?
CISA stated at publication that it had not observed exploitation, and neither CVE is in the KEV catalogue. AWS, Cloudflare and watchTowr reported exploit attempts against 109618 in the days around publication. Treat “no confirmed exploitation” as a statement about evidence, not about safety.
Do I need to patch if I run PHP-FPM instead of mod_php?
Yes. FPM is listed as affected as well. mod_php is rated more dangerous because the request executes inside the web server process, but that difference lowers risk; it does not remove it.
Can a load balancer or several FPM pools protect me?
They make the two-request variant harder to arrange, because both requests must land on the same worker. That is a reduction in likelihood on someone else's infrastructure, not a fix on yours.
How do I know whether my site was already hit?
Look for large multipart request bodies, memory-exhaustion errors at request start, new executable files in upload directories and shell processes you did not start. Web server access logs are the primary source: a burst of multipart POSTs to one path from one address is the pattern to search for.