PHP's RCE fix is 13 hours old. 235 top sites can never get it

PHP's RCE fix is 13 hours old. 235 top sites can never get it

# security# php# webdev# devops
PHP's RCE fix is 13 hours old. 235 top sites can never get itMatt Busel

Originally published at tensorust.com. TL;DR: You can tell in 60 seconds whether your PHP server is...

Originally published at tensorust.com.

TL;DR: You can tell in 60 seconds whether your PHP server is still a target, and close the hole tonight. The one-line check is below. Then the receipt: 13 hours after PHP shipped the fix for two critical unauthenticated remote-code-execution bugs, I pulled the response headers of the top 20,000 sites on the web. Of the 428 that still announce their PHP version, only 107 are on a patched release. 235 run a version PHP abandoned years ago, so no update will ever reach them.

Everyone spent today screaming CVSS 9.2 and posting fake exploits. The real story is quieter and worse: the hard part was never writing the exploit. It was getting a fix out, and it will be getting people to install it. Most won't.

Animated bar chart titled 428 sites still announce their PHP version, 321 are not on the fix. Of 15,931 of the top 20,000 sites that answered a GET request, 428 print a PHP version in a response header. Sorted by status: patched or newer 107 (25%), supported but behind the patch 82 (19%), supported with the patch level hidden 4, and end of life with no fix possible 235 (55%). Footer: only 1 in 4 is patched, and 235 run a branch PHP abandoned.
Our survey: a passive GET / of the Tranco top 20,000 (list 746PX), 11:25 PM ET Oct 21 2026, about 13 hours after the release; Server and X-Powered-By headers only. Static frame: hero.png.

What actually broke

At 14:00 UTC on October 21, the PHP project released 8.5.12, 8.4.27, 8.3.36 and 8.2.35. They fix two bugs that let an attacker who is not logged in run code on your server:

  • CVE-2026-109618 (RCE via OOM corruption): if a request hits PHP's memory limit at the wrong instant, PHP leaves half-built internal data behind and later trusts it. On Apache with mod_php, the project says an unauthenticated request can trigger this before any of your application code runs, and full remote code execution was demonstrated with default settings.
  • CVE-2026-109619 (RCE via stale global state): a fatal error at the wrong point leaves internal state pointing at memory that belonged to a previous request. The next request on that worker uses the freed memory.

Researchers at Wiz nicknamed the pair PHP2Shell. Both sit in the parts of PHP that nearly every request touches: memory management and error handling. watchTowr rated them a 10.0; PHP settled on 9.2. Either way, this is the "patch tonight" tier.

One detail the headlines skipped, and the one that should scare you most. The same bugs can leak live worker memory without running code first. That memory holds other users' passwords, session tokens, API keys and certificates. Which brings us to the 428 sites that are, right now, printing a clue to attackers for free.

Screenshot of a post by The PHP Foundation, @ThePHPF, Oct 20 2026: The PHP security team is giving advance notice. Upcoming security release Wed Oct 21st 2026 14:00 UTC, two critical vulnerabilities, both rated CVSSv4 9.2. PHP users are encouraged to prepare to update. Earlier release if details become public or active exploitation. 6.7 million views.
@ThePHPF on X, Oct 20 2026, captured 11:25 PM ET Oct 21 2026, real and unedited.

I scanned the top 20,000 sites. Here is who is exposed

At 11:25 PM ET, about 13 hours after the release, I did one harmless thing to the Tranco top 20,000 domains: a plain GET /, and read only the Server and X-Powered-By response headers from each. No bodies, no probing, no exploit, nothing a normal browser doesn't fetch. 15,931 answered.

Most sites hide their PHP version, which is good. But 428 still print it in a header. Sorting those 428 by what their banner claims:

  • 107 (25%) are on a patched point release or a newer branch. The ones who moved.
  • 82 (19%) run a still-supported branch (8.2 to 8.5) but a version below the fix. Known-behind.
  • 4 show a supported branch with the patch number hidden.
  • 235 (55%) run a branch that reached end of life. PHP 8.1 and older get nothing from the project, ever. This fix is not coming to them.

So of every site that tells you its PHP version, 3 out of 4 are not on a fixed release, and more than half are on software the maintainers walked away from. Thirteen hours in.

Bar chart of which PHP version the 428 version-announcing sites run. PHP 8.3 leads with 79, then 7.4 with 68 (end of life), 8.2 with 51, 8.4 with 41, 8.1 with 33 (end of life), 7.2 with 28 (end of life), 5.4 with 27 (end of life), 7.3 with 26 (end of life), 5.6 with 23 (end of life), 8.5 with 22, and single-digit counts down to one site each on PHP 5.2 and PHP 4.4. Red bars mark end-of-life branches that get no project fix.
Passive GET / of the Tranco top 20,000, 11:25 PM ET Oct 21 2026; one version token per site from Server and X-Powered-By.

The web is still running on museum pieces

The branch breakdown is the part I keep rereading. Among the 428, the single most common version isn't a modern 8.x. It's a tie between the current branches and the dead ones. 68 sites still serve PHP 7.4, which lost security support at the end of 2022. 28 are on 7.2. 27 are on 5.4, which went end of life in 2015. One site, in the top 20,000 on the internet, answered on PHP 4.4.

These are not patched by applying today's release. They are patched by a migration project nobody budgeted for. My honest read: a big share of them never will be, and the server is quietly a liability until the day it is quietly a breach. The version banner is not proof of vulnerability on its own, and I'll get to the caveats, but a fleet this old is its own headline.

# The 60-second check: what does your server tell strangers?
curl -sI https://your-site/ | grep -iE 'server|x-powered-by'
# If a PHP version shows and it is below 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35, update now.
# Then hide it: expose_php = Off in php.ini, or strip the header at your proxy.
Enter fullscreen mode Exit fullscreen mode

Not announcing a version is not the same as being safe. It just means an attacker has to fingerprint you the hard way. But announcing an old one is the opposite of safe: it is a welcome mat.

Two-panel card: the fast part and the slow part. The slow part, a fix stuck for about two years: the root cause was spotted in 2024 and theorized as exploitable, the security team could not agree on a fix and the work stalled and restarted repeatedly over months, which the PHP Foundation now calls a structural failure, and it only shipped after Calif, OpenAI and Wiz proved full RCE in August 2026. The fast part, thousands of proof-of-concept exploits that do nothing: GitHub filled with thousands within hours, researchers found they fail against a vanilla PHP server and mostly require the server to already be exploitable, and the LLMs wrote confident exploits that are fake.
Slow part: The PHP Foundation post, Oct 21 2026. Fast part: Elias Taylor, There isn't an easy exploit for this PHP vulnerability, Oct 21 2026.

The fast part was fake. The slow part was real

Here is what today got backwards. By this afternoon, GitHub had thousands of "PoC" exploits for PHP2Shell. Security engineer Elias Taylor stood up a vanilla PHP server and ran them himself. They don't work. Most quietly require the server to already be exploitable through a separate local-file-include bug, which is cheating. His line is the best thing written all day:

"People are being deluded by their LLMs telling them they have an exploit when they don't... the LLM giving their younger brother an unplugged controller. It says exploit all across the screen, but it's modified the server you're testing against to have a severe vulnerability."

That is the fast part, and it's noise. Now the slow part, in PHP's own words. The root cause behind CVE-2026-109618 was first spotted in 2024 while fixing an unrelated audit finding. A fix stalled. The PHP Foundation now calls that delay "a structural failure," caused by "both the security team's decision process and its lack of resources." The work "stalled and restarted repeatedly over months." It only moved after Calif, OpenAI and Wiz independently proved full RCE in August 2026.

Two years. A critical RCE in the memory core of the language that runs a huge slice of the web sat half-fixed for two years because a small, underfunded team couldn't agree on a trade-off. The LLMs that can't write a working exploit today could not have fixed this either. The thing that fixes it is a few engineers who know the whole engine, and PHP is openly begging for the money to keep them.

Timeline of the 23 hours before the fix, all times UTC. Oct 20 15:00: the two CVE IDs leak on forums with a wrong time and a wrong 10.0 score. Oct 20 19:30: PHP rushes its pre-announcement out and moves the release up a full day. Oct 20 around 20:00: Calif posts a working proof-of-concept video, then deletes it, and copies spread. Oct 21 07:41: Chainguard breaks the embargo and ships patched images 6 hours early, letting attackers diff the fix. Oct 21 14:00: the real release, PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35.
Source: The PHP Foundation, Today's PHP Security Release, Oct 21 2026, and the php.net advisory. Read 11:10 PM ET Oct 21.

And then the disclosure fell apart

The last 23 hours were a case study in how a careful embargo dies. The CVE IDs leaked on forums around 15:00 UTC on October 20, with a wrong time and a wrong 10.0 score. PHP rushed its pre-announcement out and moved the release up a full day. Around 20:00 UTC, Calif, one of the reporting firms, posted a working proof-of-concept video and then deleted it; copies spread anyway.

Then the part worth naming. At 07:41 UTC on October 21, more than six hours before the coordinated release, Chainguard unilaterally published built images containing the fix. Every other PHP user was still waiting, while anyone could now study the patch in binary form and reverse the bug from the diff. The PHP Foundation's verdict: this "disregarded weeks of work by many parties toward a coordinated disclosure." When you ship a security product, breaking the embargo to look fast is not a flex. It is handing attackers the map early.

Screenshot of a post by Mudit Gupta, @Mudit__Gupta, Oct 21 2026 12:07 PM ET: Nightmare day for cybersecurity. Multiple major security incidents, active exploits, supply chain compromises. PHP: two critical unauthenticated RCEs. LiteLLM: v1.107.0 on PyPI and Docker is backdoored. eMudhra: a certificate authority's keys were crackable. Plus Node, Next.js, React security releases and a TiDB Cloud breach. 337.1K views.
@Mudit__Gupta on X, Oct 21 2026, captured 11:25 PM ET Oct 21 2026, real and unedited.

This was one day in a brutal week

PHP didn't happen in a vacuum. As security engineer Mudit Gupta put it to 337K people, it was a "nightmare day for cybersecurity": PHP's two RCEs, LiteLLM's backdoored 1.107.0 on PyPI and Docker, eMudhra's crackable certificate-authority keys, Node and Next.js security releases, a TiDB Cloud breach, and Railway's secret exposure, all in the same 24 hours. Different bugs, one lesson: the number of serious vulnerabilities found per day is going up, because tooling now finds them faster for everyone, defenders and attackers alike.

The panic is contagious and usually overstated. One post today claimed "70% of websites are at MAJOR risk." That is the "most sites run PHP" stat dressed up as "most sites are about to be hacked," and it isn't true: plenty of PHP runs behind FPM, behind proxies, on patched distro builds, or simply not reachable the way mod_php is. The real number isn't 70%. It's the quiet, checkable one I measured: 3 of 4 sites that leak their version are not on the fix, and a quarter of those are on software that is already dead.

The honest caveats (read these before you quote me)

  • A version banner is a claim, not a scan. A site can spoof it, and some Linux distributions backport the fix without bumping the number, so a "behind" banner can already be patched. In my data only 6 of the behind-or-EOL sites carried a distribution suffix, so backport-masking is small here, but it is not zero.
  • Announcing a version does not prove you are exploitable for this bug. CVE-2026-109618 is worst on Apache with mod_php; FPM and other setups have narrower paths. Config matters.
  • Not announcing a version does not prove you are safe. The 15,000 sites that stayed quiet are simply harder to fingerprint, not patched by definition.
  • This is a one-shot snapshot of 20,000 domains at one moment, not a census of the web. The percentages describe the version-announcing sites, nothing more.

Even with every caveat, the shape holds: the fix is out, the exploit is overhyped, and the sites most likely to still be exposed are advertising it.

The numbers so far

  • Sites scanned: 20,000 (Tranco list 746PX). Responded to GET /: 15,931.
  • Announce a PHP version: 428. On a patched release: 107 (25%). Not on the fix: 321 (75%).
  • End-of-life PHP (no fix exists): 235. Still on PHP 7.4: 68. On 5.4 or older: 62. Oldest seen: PHP 4.4.
  • Hours after the release when I checked: about 13.
  • Years the root cause sat half-fixed: ~2 (spotted 2024, shipped Oct 2026).
  • Working public exploits against vanilla PHP at publish time: 0 confirmed. Fake PoCs on GitHub: thousands.

My bet, and your turn

Prediction: a year from now, a passive rescan of these same 20,000 sites still finds dozens serving end-of-life PHP, and at least one of today's known-behind sites gets popped by PHP2Shell before it ever updates. The bug gets patched in a day. The fleet takes years. If I'm wrong, I'll run the rescan live and put the numbers in the correction.

Your turn: should browsers and CDNs just strip the Server and X-Powered-By version banners by default, or does hiding the version only make everyone lazier about patching? Tell me in the replies. And @ThePHPF, the funding ask lands: who should be paying for the engine the web runs on?

Find out tonight if your app is the one leaking

If you built on a stack you don't fully audit, the scary question isn't "is PHP patched." It's "what else is my server handing to strangers." The Launch Check ($49) answers exactly that: we read your live URL the way an attacker does and tell you, worst first, what it leaks. Version banners and server fingerprints, secret keys shipped to the browser, whether a stranger can read your database (Supabase row-level security), storage buckets, admin pages, redirects, missing rate limits and security headers. Plain English, with the exact fix for each, in 48 hours. Read-only, only on a URL you own.

Guaranteed: if a problem in what we checked turns up later, we review it and write the fix at no extra cost. Email support@tensorust.com and a real person replies within one business day. All sales final, no refund needed, because we keep working until it's right.

Related on tensorust.com: LiteLLM got backdoored again: check your keys in 5 minutes, a landing-page grader tested on 2,077 Show HN pages, and Theo's 60% stat is an outage chart.

Follow for one checked, exploitable-today security fix for builders a day, measured on real data, not vibes.

Method and data: passive survey run 11:00 to 11:25 PM ET Oct 21 2026 against the Tranco top 20,000 (list 746PX, generated Oct 21 2026). One GET / per domain over HTTPS then HTTP, following up to six redirects, reading only Server and X-Powered-By response headers; no request bodies were read and nothing was probed or exploited. A PHP version token was classified against the fixed point releases (8.5.12, 8.4.27, 8.3.36, 8.2.35); branches 8.1 and older were counted as end of life. Per-domain data was aggregated and the raw file discarded; no site is named. Incident facts from the php.net advisory, The PHP Foundation's October 21 2026 post, Wiz's PHP2Shell writeup, and Elias Taylor's analysis, all read 11:10 PM ET Oct 21 2026. X screenshots captured 11:25 PM ET, real and unedited.