If you run Apache with mod_php, stop reading and patch now: upgrade to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35.

Two new RCE bugs in PHP’s core runtime affect versions back to 5.4, and Apache/mod_php setups are known exploitable today. A longtime PHP defender explains how the bugs work, why patching is the only real fix, and what to do right now.

October 21st, 2026

Hello, I spent many years defending a large modern PHP application. The new bugs are bad! You should fix them. The runtime will be fine. I promise. Just do it.

So, what exactly happened? LLM-assisted vulnerability discovery found some novel applications of memory corruption problems that let you abuse improper cleanup of failed/broken/interrupted web requests.

It’s very clever! Sometimes, LLMs and humans together do amazing things.

GHSA-w8hw-w9fx-j79w - RCE via OOM corruption

The really not so good one is GHSA-w8hw-w9fx-j79w, because it lets you write arbitrary memory state into a place where it will be read (and potentially executed) during request shutdown, a normal part of the PHP request lifecycle. Some common PHP deployment strategies always exercise a shutdown branch before any application code is handled - meaning it does not matter what your application does - if it receives requests it is vulnerable.

Due to mod_php’s behavior, you can reliably trigger this by simply exhausting request memory. There are a few ways to do this, none of which I will describe to you, but I will tell you that someone with a journeyman familiarity with PHP could figure it out given some breadcrumbs. Apache and mod_php unfortunately let this trigger before any application code runs: any PHP application that can receive web requests is exposed. If you are using Apache with mod_php you have to fix this NOW; the validated exploit targets unpatched Apache/mod_php. Source analysis indicates it is likely that FPM, FrankenPHP, and LSAPI are also affected.

Our research team tested how low the bar is: we gave two open-weight models the task of finding the RCE using only public information, and for less than the cost of a coffee, both reproduced the issue and achieved RCE. Public exploits are already being posted. Patch now.

Terminal output reading “RCE achieved, verified on two completely different setups,” showing arbitrary command execution as the www-data user on the php:8.4.26-apache and php:8.5.11-apache Docker images.

An open-weight model achieved remote code execution on stock PHP/Apache, one patch release behind the fixes (8.4.26 and 8.5.11).

GHSA-6wmf-4rv5-p3rp - RCE via stale global state

Let me be perfectly clear - this bug being harder to exploit does not make it less dangerous. Once somebody does it once, a tool will arise to make replaying that gadget trivial. We have done this dance already with BinaryFormatter et al.

Patching is the only defense.

I have a somewhat old-school view of bugs that require heap grooming, which is that doing it is hard and gross. LLMs have probably changed the calculus on this a little, but I suspect a skilled operator will do much better than a novice: successful exploits of LLM-assisted heap grooming attacks will be launched by…people who were gonna do it anyway after writing the exploits by hand for months. Therefore, while GHSA-6wmf-4rv5-p3rp is also Not Good, I am somewhat less worried about it in the short term compared to its evil twin.

It is also NEATO and a cool variant of my favorite bug class: insecure deserialization.

Basically, it is a language behavior primitive that lets you abuse improper state cleanup to write to global state. This is an incredibly dangerous primitive because it’s related to our first bug via the request lifecycle. 

A PHP worker has its own memory heap, and as part of normal behavior zeroes it out when it dies. Except for when it doesn’t. This is a Producer of a potentially hazardous state.

A PHP worker has its own memory heap, and as part of normal behavior zeroes it out on initialization before it ever reads from it. Except for when it doesn't. This is a Consumer of potentially hazardous state. This is akin to a deserialization gadget - functionality that allows Bad Things To Happen.

There are two known consumers of potentially poisoned state: INI diagnostics and session upload progress. Some runtimes, like mod_php, also do things like read php.ini once on startup then persist forever. This is Very Super Not Good if you can, you know, use a known producer to write arbitrary stuff to that state.

This bug is harder to exploit. Both the producer and the consumer must reside in the same worker. Both consumer types have been shown to be exploitable vs Apache/mod_php, and session upload progress has been shown to be exploitable against Apache/mod_php and FPM. It’s probable that we’ll end up finding exploitable cases in FrankenPHP and LSAPI too.

This is how it is now. Weird edge case “you’d need to be clairvoyant to…” bugs are getting unearthed. There will be more.

What to do and what we’re doing

What to do now: upgrade to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35. On end-of-life 8.1, 8.0 or 7.4, apply the available backports and then immediately plan an upgrade - do not depend on cherry-picked commits for bugs in core runtimes, ever. While you are upgrading there are partial mitigations such as setting session.upload_progress.enabled=0 and leveraging relevant firewall rules which attempt to block known payloads however this is not a strategy we recommend to rely on as both can be bypassed.

What we’re doing: Semgrep Guardian now flags vulnerable PHP versions when your agent starts working on a project, and coverage for source-code defined usages of PHP is on the way.