Mr. Nice Try Notes from the edge

· 7 min read

The PHP bugs, explained with a kitchen

PHP just patched two critical bugs, CVE-2026-109618 and CVE-2026-109619, that let a stranger run their own code on a website's server. Here's what they are in two sentences, what that means if you've never touched PHP, and a restaurant kitchen that explains the rest.

The bugs

On Wednesday, October 21 at 14:00 UTC, PHP shipped fixes for two critical bugs:

  • CVE-2026-109618, "RCE via OOM corruption." When a request runs PHP out of memory partway through, PHP abandons it with its internal data half-built, and the cleanup afterwards treats that half-built data as valid.
  • CVE-2026-109619, "RCE via stale global state." Data that belongs to one request can survive after its memory has been freed, and the next request handled by the same PHP process can use it before PHP resets it.

Both are rated CVSS 9.2 out of 10. Both are use-after-free bugs: PHP uses memory it has already handed back. Every known way to trigger them is an ordinary file-upload request (multipart/form-data). PHP's advisory says complete remote code execution was "validated over HTTP," and PHP's release notes say "there are no complete mitigations, updating is the only safe choice."

They weren't secret for long. Details leaked the day before, and Cloudflare saw the first attacks at 07:43 UTC on Wednesday, more than six hours before the fix shipped.

2critical bugs in PHP itself
9.2CVSS v4.0, each
07:43UTC, first attacks seen
14:00UTC, the fix shipped

What does that even mean?

If that was a lot of jargon, here's the short version: a stranger on the internet could make a website's server run their own code, without logging in, by sending it one carefully built request.

PHP is the language behind a huge share of websites. WordPress runs on it, and so do Laravel, Magento and a lot of the sites you've never thought about. And this bug is in PHP itself, not in any one website. A site with perfectly written code was still exposed.

On Wednesday, a few hours after the patch, someone on X asked for an explanation a six-year-old could follow. This is what I wrote:

A lot more people read that than anything else I've written about this, so here's the long version.

The kitchen

A panicking elephant cook in a chef's hat juggles too many pans while a little robot at the order window shouts an order so long the ticket loops across the kitchen floor. Mr. Nice Try leans in the doorway with a coffee, one eyebrow raised.

Think of a website as a restaurant.

  • You, the visitor, are a customer. Every time you open a page, you place an order.
  • PHP is the kitchen. It takes the order, cooks the page and sends it out on a plate.
  • The kitchen has cooks. Each cook takes an order, cooks it, sends it out, and takes the next one. A cook doesn't go home between orders. One cook handles hundreds of orders in a row.
  • Each cook has a counter. It's where the ingredients for the current order go. The counter is only so big.

The whole thing works because of one habit: before the next order, the cook wipes the counter. Whatever was there for the last customer gets thrown out, so the next customer's food starts clean.

Both bugs break that habit.

Bug one: shout a large order

Someone walks up to the order window and shouts an order so big it doesn't fit on the counter.

The cook panics. He drops everything, mid-chop, and walks away from the order. That's fine on its own. Kitchens are built for orders that can't be finished.

The problem is what happens next. When the order is abandoned, someone comes by to clean up, and they treat the half-made mess on the counter as if it were a finished dish. Things that were never filled in get handled as if they were.

That's CVE-2026-109618.

Bug two: leftovers on the counter

The elephant cook is busy at the stove with the next order, next to a counter nobody wiped. A little robot who crept in through the back door drops something rotten, with coral stink lines, onto a plate waiting under the heat lamp. Mr. Nice Try peeks in from the edge with a magnifying glass.

Sometimes the counter doesn't get wiped. Scraps from the last order, food that was supposed to go in the bin, are still sitting there when the next order comes in. And before the cook gets around to wiping, the next order grabs some of it.

That's CVE-2026-109619. And the panic in bug one is one of the ways to leave a mess behind.

Where the stranger comes in

On its own, a messy counter just means the odd bad plate. Annoying, not dangerous.

But a stranger who understands the kitchen can do more than make a mess. They place the first order to leave exactly the scraps they want on the counter, and a second order to make the cook use them. Now they decide what goes on the plate.

In a kitchen, that's something rotten served to a customer. On a server, it's the stranger's own instructions, carried out with the kitchen's keys: the website's files, its database password, its API keys.

It can also go the other way. Leftovers from someone else's order can end up on the stranger's plate. On a server, that's other visitors' data: passwords, session tokens, keys.

Back to the technical

Here's the same kitchen, with the real names:

In the kitchen In PHP
The restaurant A website
An order An HTTP request
The kitchen PHP itself
A cook A PHP worker process (PHP-FPM or Apache's mod_php), which handles request after request
The counter The worker's memory
Wiping the counter PHP resetting its state at the start of each request
Shouting a large order A multipart/form-data request (a file upload) built to cross memory_limit
The cook panics An out-of-memory error: PHP jumps out of the request (longjmp()) halfway through setting it up
Treating the mess as a dish Shutdown treating half-built request data as valid (CVE-2026-109618)
Leftovers grabbed by the next order Global state that points at freed memory, used by the next request before it's reset (CVE-2026-109619)
Arranging the scraps Shaping the heap so the freed memory holds the attacker's data
Something rotten on the plate Remote code execution, as the web server's user
Someone else's food on your plate Memory disclosure

A few things fall out of that table.

It's the kitchen, not the recipe. Your code is the recipe. These bugs happen while PHP is still reading the request, before WordPress, Laravel or your own code has run a line. Nothing in your app could stop them.

The order window is the way in. Every known trigger is a file-upload request. That's why blocking uploads you don't expect, in front of PHP, helps even when you can't patch yet.

Hiding the whiteboard wasn't enough. Before the patch, the best lead was a feature called session upload progress. Think of it as a whiteboard where the cook notes how much of a big order has arrived. My post on Tuesday night said to switch it off, and PHP's advisory does list it as one place that grabs leftovers. But it isn't the only one: the warnings PHP writes about its own settings, before a request is set up, can grab them too. A PHP core developer warned that turning off upload progress alone isn't enough.

The fix is a cook who always wipes the counter. That's what the patch does: it resets the state properly, every time, whatever happened to the last order. Nothing else does that completely.

What to do

The elephant cook calmly wipes a spotless counter with a cloth in his trunk. At the order window, Mr. Nice Try holds up a palm to a deflated little robot holding an enormous rolled-up order.

  1. Update PHP to 8.5.12, 8.4.27, 8.3.36 or 8.2.35: servers, containers, base images, serverless runtimes. If your host manages PHP, ask them whether they have.
  2. On PHP 8.1 or older, there's no official release. PHP published minimal source backports for 7.4, 8.0 and 8.1, and some Linux distributions and LTS vendors ship their own fixes. Otherwise, move to 8.2 or later.
  3. Until you can patch, the advisories list partial mitigations: block multipart/form-data requests you don't expect at your WAF or proxy, set session.upload_progress.enabled=0 and fatal_error_backtraces=0, and keep post_max_size small. The Tuesday post has the how-to for php.ini, .htaccess, nginx, Caddy, Cloudflare and WAFs.
  4. Look back at the window before the patch. Uploads to URLs that don't take uploads, bursts of them across many sites, PHP workers crashing, or PHP running sh, curl or wget. If you find signs someone ran code, treat the server as compromised: rotate every secret it could read, and rebuild it.

Sansec, who track these attacks, say mass exploitation has been less likely than first feared, because the public exploits need specific knowledge of the server. That's a reason to stay calm, not a reason to wait.

On the Edge, the proxy I run in front of a few thousand sites, Tuesday night's rule that blocked the upload progress field is now broader: any multipart request a site doesn't expect gets a 403 before it reaches the kitchen.

The kitchen's open again. Wipe the counter.

I'm @MrNiceTry on X.

Sources: PHP's October 21 security release; the advisories for CVE-2026-109618 and CVE-2026-109619; Sansec on PHP2Shell, including Cloudflare's first sighting at 07:43 UTC.