← go home

PHP 2Shell: the vulnerability that reminds us PHP is everywhere

On October 21, 2026, the PHP Foundation released a critical security patch for two remote code execution bugs. By October 26, CISA had added both to its Known Exploited Vulnerabilities catalog. By October 29, researchers had confirmed active exploitation in the wild — attackers chaining the bugs with a Linux kernel privilege-escalation flaw to get root on internet-facing servers.

I write about self-hosting, and I run PHP. So I checked my own house. Here's what I found, and what the bugs actually are.

The two bugs

They're called php2shell: CVE-2026-109618 and CVE-2026-109619. Both are rated CVSS 9.2 (Critical) under CVSS 4.0. Both allow unauthenticated remote code execution — no login, no CSRF token, no special header. Send the right request to a PHP-powered web server and you can run code as the PHP process.

The root cause of both is the same class: use-after-free via longjmp().

PHP's fatal-error handling has historically used longjmp() — a C function that jumps back up the call stack to a saved point. It's a fast, ugly escape hatch from deep in the engine. The problem, as the PHP advisory describes it:

  • CVE-2026-109618: When an out-of-memory error triggers longjmp(), the request's memory is left uninitialized. An attacker who can reliably trigger OOM (large upload, deep recursion, crafted input) gets to read and branch on that garbage memory — which is enough to reach RCE.
  • CVE-2026-109619: When longjmp() fires, some global memory is left pointing at a region that's already been freed. A later, seemingly unrelated request can read or branch on that stale pointer. This one is nastier because the trigger and the exploit can be different requests.

A word of caution on my own framing: longjmp()-based error handling is an old design in PHP's engine, but I'm describing the mechanism, not claiming it was "designed in 1995 and never touched." The PHP team's own write-up is the authority on the history; what's clear is that the fatal-path handling is where the memory discipline broke down.

Why this one's different

Most "patch your CMS" CVEs are in a component — a plugin, a framework, a library. These are in the engine itself, affecting all PHP versions that serve web requests:

  • Apache with mod_php (PHP considers this the highest-risk configuration)
  • PHP-FPM
  • php-cgi
  • FrankenPHP
  • LiteSpeed

And the scale is the kicker: Palo Alto Networks' Xpanse telemetry counted 22.6 million+ exposed instances potentially vulnerable. That's not a niche. That's "a meaningful fraction of the web."

The fixed versions, released 2026-10-21:

  • PHP 8.5.12
  • PHP 8.4.27
  • PHP 8.3.36
  • PHP 8.2.35

PHP 8.1 and earlier are end-of-life and have no patch. If you're on those, the CISA guidance is blunt: take the system offline until you can upgrade, or put a WAF in front as a stopgap.

I checked my own house

I run Nextcloud on a Proxmox LXC (CT 114). Nextcloud is PHP. So the question was: what version am I on?


$ docker exec nextcloud php -v
PHP 8.5.12 (cli) (built: Oct 21 2026 15:49:40) (NTS)

8.5.12 — the exact patched version. And the build timestamp is Oct 21, 2026, the day the fix shipped. My Nextcloud Docker image had already pulled the patched PHP by the time CISA wrote their alert. I was not in the 22.6 million.

That's a relief, but it's also a reminder of how thin the margin is. I wasn't safe because I did something clever — I was safe because the Docker image maintainer rebuilt fast. A self-hosted PHP install that wasn't updated that day would have been sitting in the exploited set for a week.

A few things I'd tell anyone running PHP self-hosted:

  1. Inventory your PHP. It hides inside other software (Nextcloud, WordPress, any CMS, the admin UI of a router or firewall — that's exactly how the PAN-OS hits happened). find / -name 'php*' -type f 2>/dev/null is a start.
  2. Internet-facing first. If a PHP box talks to the public internet, it patches before everything else.
  3. Watch for spawned shells. The post-exploitation signature is a PHP worker process launching /bin/sh or downloading a tool. CISA published a SIGMA rule for this if you have log aggregation.
  4. EOL PHP is a decision, not a default. 8.1 and earlier aren't just unpatched — they're a promise you'll be the one finding out about the next RCE.

The timeline

| Date | Event |

|---|---|

| Oct 21, 2026 | PHP Foundation releases 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 |

| Oct 21, 2026 | CISA issues "Critical Vulnerabilities in PHP Require Immediate Patching" alert |

| Oct 26, 2026 | CISA adds both CVEs to the KEV catalog |

| Oct 29, 2026 | Unit 42 / Dream Research confirm active exploitation (php2shell + Linux kernel LPE → root on internet-facing PAN-OS management interfaces) |

The five days between the patch and the confirmed in-the-wild exploitation is the number to remember. That's the window where an unpatched, internet-facing PHP box is most likely to get hit.

What it means for a homelab

I don't run a lot of PHP. Nextcloud is the main one, and it's containerized (which is a genuine advantage — the image maintainer does the patching, you just update the image). But the lesson isn't PHP-specific: the boring, old, everywhere technologies are the ones that get 22 million exposures. Apache, PHP, a Linux kernel — none of them are new, none of them are "modern," and all of them are the reason a "self-hosted" box is still a target the moment it touches the internet.

Self-hosting doesn't make you smaller. It makes you responsible.