Blog
10.21.26

11 PHP2Shell — You Can Patch and Still Be Exploitable

Damiano Bolzoni
Co-founder & CTO

TL;DR

Two flaws in PHP itself — CVE-2026-109618 and CVE-2026-109619, both CVSS v4.0 9.2 — allow unauthenticated remote code execution as the web worker account. Details leaked a day before the patch, so the window opened before the fix was delivered. PHP shipped 8.5.12, 8.4.27, 8.3.36 and 8.2.35 on 21 October. Critically, one of the two bugs lives in already-running workers, so a pool that has not been restarted stays exploitable on patched binaries. Patch, restart every pool, verify the restart, then hunt by behavior.

What it is

Two separate bugs in the PHP interpreter, disclosed together and nicknamed PHP2Shell after an exploit tool that appeared in a leaked screenshot.

CVE-2026-109618 is in PHP's out-of-memory handling. If PHP runs out of memory part-way through setting up request data, that setup is interrupted and the data is left partially initialized. Cleanup then treats it as valid, and from there you get a path to code execution.

CVE-2026-109619 is a stale-state bug. PHP holds request-specific state after the memory backing it has been freed. If the same worker handles a later request, that request can reach the stale state before normal initialization resets it. That is a heap use-after-free, and it can also leak memory contents to the attacker.

Both are rated CVSS v4.0 9.2. Both allow remote code execution without authentication, running as the web worker account. The PHP project rates mod_php the highest risk, because the interpreter runs in-process with the web server, but PHP-FPM, php-cgi, FrankenPHP and LiteSpeed are all in scope. Every platform PHP runs on is affected.

Details leaked on 20 October, a day ahead of the fixes, necessitating a rapid response.

Why it matters

It is below everything you built. Both bugs fire during early request parsing, inside the interpreter. This occurs before authentication, before your framework boots, and before any application logic you wrote gets a say. Your app-layer WAF rules sit above that and do not see it. The vulnerable surface is not your code; it is the thing your code runs on.

The attacker had a head start. The leak preceded the patch by a day. Reporting disagrees on how far exploitation has progressed. watchTowr says its honeypot network observed exploitation on 21 October, Huntress reports no confirmed indicators of compromise, and at the time of writing it is not in CISA's KEV catalog. Treat the disagreement as a reason to look, not a reason to wait.

You can be patched and still exploitable. If you’re the one who signs off on the fix, this is the most important thing to know about this flaw. CVE-2026-109619 is a flaw in the state a long-lived worker carries between requests. Updating the binary on disk does nothing to a worker process already running with the old interpreter loaded. Until that process is recycled, it is still vulnerable and still serving traffic.

So an estate can read as fully remediated by every measure a scanner uses — correct package version on every host, inventory green, finding closed — and remain fully exploitable on every host where nobody bounced the pool. "Patched" is a claim about binaries. Exposure is a property of running processes. Those are different facts, and most programs only measure the first.

How to fix it

As noted, pay specific attention to Step 3.

  1. Inventory every PHP install. This means every install: cPanel, Plesk, appliances, Windows applications, container images, anything bundled. If the count is wrong here, everything downstream is wrong too.
  2. Patch to the fixed release on each branch: 8.5.12, 8.4.27, 8.3.36, 8.2.35. Linux distributions and LTS vendors received the patches in advance, so check your vendor for updated packages before building anything yourself.
  3. Restart every PHP-FPM pool and every web server. This is not optional. Without it, CVE-2026-109619 survives the patch in any worker that was already running.
  4. Verify the restart actually happened. Check process start times, not package versions. This is the only step that distinguishes a closed finding from a finding that merely looks closed.
  5. Handle 8.1 and older. Those branches get no project release. The PHP project has published patches to help distributions backport fixes to 7.4, 8.0 and 8.1, so check your vendor before assuming you are stranded. Where nothing exists, move the branch forward or take the host off the internet until you can.

‍If you cannot patch this hour, there are stopgaps: block multipart/form-data at the proxy, set session.upload_progress.enabled=0, and on 8.5 set fatal_error_backtraces=0 via server config then restart workers. These stopgaps close specific attack paths, but they do not make an install safe. Treating them as a permanent fix is how a two-day exposure becomes a two-month one.

Then hunt, because patched does not mean you were not already hit. There are no published hashes and no reliable IP list, so detection is behavioral. A successful attack looks like a PHP worker spawning a child process it has no business spawning. Alert when php-fpm, php-cgi, httpd or apache2 launch:

  • shells and interpreters — sh, bash, cmd.exe, powershell, python, perl
  • download tooling — curl, wget, nc, certutil.exe
  • reverse-shell patterns — /dev/tcp/, fsockopen, mkfifo
  • reconnaissance from the web tier — whoami, id, uname -a, ipconfig

Preserve web and PHP logs while you do it. The leak gave attackers a head start measured in days, and the evidence of that window is in logs that rotate.

‍

The patch was the easy part

It is worth noticing the shape of this one. The upstream fix existed within a day of the leak. Nobody is debating whether the patch is correct, whether 9.2 is the right severity, or whether it is worth doing. There is no prioritization question here at all.

The hard part is everything after that. You have to find every install, update each one, restart every pool, check that the restarts happened, hunt without indicators, and deal with the old versions that get nothing. Some organizations will get through that in hours and others will take three weeks. It does not matter that they likely all read the same advisory on the same day.

That’s the reality now. So far, nobody has reported PHP2Shell being exploited. But attackers are getting faster, and before long even the teams that patch and restart within hours may be too slow. PHP2Shell also got this much attention because it leaked. Most serious flaws don’t get a press cycle. How many are sitting in your environment right now that nobody is writing about?

That’s why Kai exists. Kai maps your internet-facing PHP footprint and flags likely-vulnerable hosts by version, non-destructively, against assets you authorize. If you want a scoped PHP2Shell exposure review, ask.

Sources

PHP project security releases, 21 October 2026 — 8.5.12, 8.4.27, 8.3.36, 8.2.35. GitHub advisories list every release prior to these as affected. https://www.php.net CVE-2026-109618 (CVSS v4.0 9.2) — out-of-memory handling; partially initialized request data treated as valid during request cleanup, yielding a path to code execution. CVE-2026-109619 (CVSS v4.0 9.2) — request-specific state retained after its backing memory is freed; a later request on the same worker may reach that stale state before initialization resets it. Heap use-after-free and memory disclosure.Affected runtimes per the PHP project: PHP-FPM, Apache with mod_php (rated highest risk), php-cgi, FrankenPHP, LiteSpeed.Huntress — Rapid Response: php2shell, Leaked Critical PHP Vulnerabilities. Reports no confirmed indicators of compromise. https://www.huntress.com/blog/php2shell-leaked-critical-php-vulnerabilitieswatchTowr — PHP Remote Code Execution FAQ: CVE-2026-109618. Reports exploitation observed via its Attacker Eye honeypot network on 21 October. https://watchtowr.com/intelligence/php-cve-2026-109618-faq/Sansec — "php2shell" is the name of an exploit tool seen in a leaked screenshot, credited to Calif.IO. Details leaked 20 October, a day ahead of the patch. End-of-life branches: 8.1 and older receive no project release. The project has published patches to assist distribution backports for 7.4, 8.0 and 8.1. Detection guidance and response sequence: Kai Security threat advisory, PHP2Shell, 21 October 2026.