Jorge Turbica / blog · Blog ← All articles ES · Leer en español
Languages

php2shell: unauthenticated RCE in PHP 5.4 through 8.5, and exploits are already out

Two critical bugs (CVSS 9.2) in the PHP runtime allow unauthenticated code execution. 8.2–8.5 are patched; 8.1 and earlier get no fix.

A leak pulled the patch forward by 24 hours, and the exploits still beat a lot of upgrades. CVE-2026-109618 and CVE-2026-109619, nicknamed php2shell, are two memory-handling bugs in the PHP runtime itself. Rated CVSS 9.2, they affect every version from 5.4 through 8.5.11 and allow unauthenticated remote code execution. Wiz Research confirmed it against Drupal and WordPress installs.

What is broken, and why updating your CMS won't help

Both bugs show up when PHP aborts a request halfway through and then cleans up badly:

CVEWhat goes wrong
CVE-2026-109618An out-of-memory error interrupts a request while some internal data is still uninitialized; cleanup then treats it as valid.
CVE-2026-109619After a fatal error, PHP keeps references to memory that has already been freed; the next request served by the same worker can follow them and expose another request's data.

All an attacker needs is crafted HTTP requests, and large requests are one way to push memory pressure. From there they can crash the process, read memory they shouldn't see or run their own code. The operational point is that the flaw lives in the interpreter: updating WordPress, Magento or a plugin fixes nothing. You have to replace the PHP binary, or ask your hosting provider to do it if they manage PHP for you.

Which versions fix php2shell

BranchPatched in
8.58.5.12
8.48.4.27
8.38.3.36
8.28.2.35
8.1 and earlierNo fix (end of life): move to 8.2 or newer

That last row is the painful one. Teams still on PHP 7.4 or 8.1 don't have a patch to apply. They have a branch migration to do while a public exploit is going around.

A two-month embargo that broke in a day

The timeline explains the rush. Wiz Research found the first bug on August 19, 2026, using its Wiz Atlas tool together with Gemini 4 Argon and GPT-5.6 Sol. It confirmed remote code execution against Drupal and WordPress over the next two days and reported it to the PHP security team on August 24. The fix was scheduled for October 22 at 14:00 UTC.

Around 15:00 UTC on October 20, the CVE IDs started circulating on forums and social media, with the wrong release time and a CVSS of 10.0 that wasn't the real score. PHP moved its pre-announcement up to 19:30 UTC and the release to October 21 at 14:00 UTC. Around 20:00 UTC, Calif, one of the firms that had reported the bugs, mistakenly published a video showing its proof of concept working against several targets. It was taken down, but copies sped up the public exploits.

I take two things from this. First, models now find the bug and build the exploit, not just help write the fix, so expect more serious vulnerabilities per year. Second, with this many parties under embargo (Calif, Wiz, OpenAI, Quarkslab, WAF vendors and clouds), the real window between notice and attack is measured in hours.

How to check what you're actually running

Check the version inside what runs in production, not in the Dockerfile. This command exits non-zero when the version is unpatched, so it doubles as a CI step:

bash
php -r '
$fixed = ["8.5" => "8.5.12", "8.4" => "8.4.27",
          "8.3" => "8.3.36", "8.2" => "8.2.35"];
$branch = PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;
if (!isset($fixed[$branch])) {
  echo PHP_VERSION, ": unpatched branch, move to 8.2+\n"; exit(2);
}
$ok = version_compare(PHP_VERSION, $fixed[$branch], ">=");
echo PHP_VERSION, $ok ? ": patched\n" : ": VULNERABLE\n";
exit($ok ? 0 : 1);'

For containers, rebuild with a fresh pull of the base image and check the result before you deploy:

bash
docker build --pull --no-cache -t my-app:php-patched .
docker run --rm --entrypoint php my-app:php-patched -v

And to find Kubernetes pods running images that look like PHP from their name:

bash
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}' | grep -i php

An image called api with PHP inside won't show up there, which is what image scanners are for. On Google Cloud, Artifact Analysis already flags these CVEs on new and existing artifacts.

What each platform does for you

On Google Cloud, App Engine standard on PHP 8.2 or newer updates itself. So do Cloud Run and Cloud Run functions, but only with automatic base image updates turned on. Without them, or if you ship your own image, you have to rebuild and redeploy. App Engine flexible, GKE and Marketplace solutions that bundle PHP, such as a LAMP stack or a CMS, need you to redeploy.

A WAF buys time, it doesn't fix anything

Cloudflare turned on php2shell rules at 03:02 UTC on October 21, roughly nine hours before disclosure. They're on by default on every plan with WAF, the free one included. Cloudflare has already seen attack traffic, plus payloads mutated to slip past the rules. These detections are the first to use its new "full transaction detection", which looks at the request and the origin's response together and can block a response that shows an exploit worked.

Cloud Armor only protects you automatically if managed rules are already on. If they aren't, Google asks for at least the File Upload and RFI categories, tested first in preview mode. It also asks for a rule that rejects request bodies larger than the inspection limit, because the attack can use large payloads precisely to force the out-of-memory condition.

Both vendors say the same thing: the WAF is an extra layer while you upgrade, not the fix.

Checklist before you close the incident

  • Full inventory: servers, CI base images, containers, functions and any Marketplace LAMP or CMS.
  • Running version verified with the command above, staging included.
  • PHP-FPM workers and web servers restarted after the package upgrade, since the old binary stays in memory until then.
  • A dated plan for everything on 8.1 or earlier.
  • WAF events reviewed back to October 20. On Cloudflare, that's Security > Security Analytics > Events, filtered by the rule IDs in the advisory.
  • If an exposed server stayed unpatched and those logs show matches, treat it as compromised: rotate its secrets and rebuild the machine instead of cleaning it.

Jorge Turbica

Software Engineer and SRE. I write about the real challenges I run into in production.

See portfolio ↗