# PHP2Shell CVE-2026-109618 and -109619: Patch, Then Hunt

> Two PHP core flaws, CVE-2026-109618 and CVE-2026-109619, allow unauthenticated remote code execution against PHP that serves web requests. CISA added both to the KEV catalog on October 26 with a three-day deadline. Here are the fixed versions, why php -v can mislead you on distribution builds, the stopgaps PHP itself recommends, and what to hunt for.

- URL: https://firewallsync.com/posts/php2shell-cve-2026-109618-cve-2026-109619-patch-and-hunt/
- Site: FirewallSync (https://firewallsync.com/)
- Topic: Security Operations
- Tags: vulnerability management, incident response, php, remote code execution
- Published: 2026-10-27
- Author: John Marshall

## Key takeaways

- CVE-2026-109618 (RCE via out-of-memory corruption) and CVE-2026-109619 (RCE via stale global state) are flaws in PHP itself, not in a framework or CMS. Every PHP installation that serves web requests is in scope: PHP-FPM, Apache mod_php, php-cgi, FrankenPHP and LiteSpeed.
- Upstream fixes are PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12, released October 21-22, 2026. PHP 8.1 and older get no upstream release; the PHP security team published source backports for 7.4, 8.0 and 8.1, and distributions ship their own patched packages.
- On distribution builds, php -v is not enough. An Ubuntu 24.04 package we inspected reports PHP 8.3.6 but its changelog lists the fix for both CVEs. Check the package changelog, not the version string.
- CISA added both CVEs to the KEV catalog on October 26, 2026, with a federal due date of October 29 and the forensic triage flag set. Amazon reported exploitation attempts from October 17; honeypot operators reported no confirmed successful RCE as of October 23.
- If you cannot patch today, PHP's own stopgaps are memory_limit=-1 set non-overridably, a low post_max_size and session.upload_progress.enabled=0, applied before request parsing and followed by a worker restart. They reduce specific attack paths; they do not make PHP safe.



CVE-2026-109618 and CVE-2026-109619, which the security community has nicknamed "PHP2Shell", are two memory-safety flaws in PHP's core that can give an unauthenticated attacker remote code execution on a server running PHP for the web. The fixes are PHP **8.2.35, 8.3.36, 8.4.27 and 8.5.12**. CISA added both CVEs to its Known Exploited Vulnerabilities (KEV) catalog on October 26, 2026, and gave federal agencies until **October 29** to act.

These are bugs in the PHP interpreter, so they apply regardless of your framework or CMS. If you run PHP behind a web server, update the PHP package today, restart every PHP worker, then look for signs that someone got in first. Everything below comes from the PHP project's advisory and CVE records and CISA's KEV entry unless we say otherwise.

## Are you affected?

The CVE records list PHP 8.2 before 8.2.35, 8.3 before 8.3.36, 8.4 before 8.4.27 and 8.5 before 8.5.12 as affected. PHP's advisory adds who is at risk: "all PHP installations serving web requests, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed." It rates mod_php highest, "with a demonstrated exploit where an unauthenticated request can trigger the attack before any application code runs."

| Branch | Vulnerable upstream | Fixed upstream |
|---|---|---|
| 8.5 | below 8.5.12 | 8.5.12 |
| 8.4 | below 8.4.27 | 8.4.27 |
| 8.3 | below 8.3.36 | 8.3.36 |
| 8.2 | below 8.2.35 | 8.2.35 |
| 8.1 and older | not listed in the CVE records; no upstream fix | vendor backport, PHP's source backport branches for 7.4/8.0/8.1, or upgrade |

The CVE records only list 8.2 to 8.5. Do not read that as "8.1 is safe": PHP says 8.1 and older "no longer receive updates" and published source backports for 7.4, 8.0 and 8.1 because of the severity.

### Why `php -v` can mislead you

Most production PHP comes from a distribution or a container base image, and those vendors backport fixes without changing the upstream version number. PHP says Linux distributions and LTS vendors "received the patches in advance".

We checked an Ubuntu 24.04 host. `php -v` reports 8.3.6, which is far below 8.3.36, yet the package changelog shows the fix:

```console
$ dpkg -l php8.3-cli | tail -1 | awk '{print $2, $3}'
php8.3-cli 8.3.6-0ubuntu0.24.04.13
$ zcat /usr/share/doc/php8.3-cli/changelog.Debian.gz | head -4
php8.3 (8.3.6-0ubuntu0.24.04.13) noble-security; urgency=medium

  * SECURITY UPDATE: Remote RCE via state corruption issue
    - debian/patches/CVE-2026-109618_109619.patch: Avoid state corruption via
```

So for a distribution build, search the package changelog for the CVE IDs. On Debian or Ubuntu, `zcat /usr/share/doc/php*-common/changelog.Debian.gz | grep -m1 CVE-2026-109618` works; on RPM-based systems the equivalent is `rpm -q --changelog <php package> | grep CVE-2026-109618` (illustrative; we did not run the RPM form). For official `php` Docker images and source builds, the upstream version is the one that counts.

Also check the binary that actually serves traffic. The CLI, `php-fpm` and `libapache2-mod-php` can come from different packages and be updated at different times.

### A version check for upstream builds

This script compares upstream version strings against the fixed releases. We ran it with PHP 8.3 CLI (`php php2shell-check.php 8.2.34 8.4.27 8.1.31`). It cannot see distribution backports, so a "VULNERABLE" result on a distro build means "check the changelog", not "definitely exposed".

```php
<?php
// Compares upstream PHP versions with the fixed releases for
// CVE-2026-109618 / CVE-2026-109619. Does not detect vendor backports.
$fixed = ['8.2' => '8.2.35', '8.3' => '8.3.36', '8.4' => '8.4.27', '8.5' => '8.5.12'];

function status(string $v, array $fixed): string {
    $branch = implode('.', array_slice(explode('.', $v), 0, 2));
    if (!isset($fixed[$branch])) {
        return version_compare($v, '8.2', '<')
            ? 'END OF LIFE: no upstream fix; needs vendor backport or upgrade'
            : 'UNKNOWN branch: check php.net';
    }
    return version_compare($v, $fixed[$branch], '>=')
        ? "fixed upstream (>= {$fixed[$branch]})"
        : "VULNERABLE upstream (< {$fixed[$branch]}) unless your vendor backported the fix";
}

foreach (array_slice($argv, 1) ?: [PHP_VERSION] as $v) {
    printf("%-10s %s\n", $v, status($v, $fixed));
}
```

```console
$ php php2shell-check.php 8.2.34 8.4.27 8.1.31
8.2.34     VULNERABLE upstream (< 8.2.35) unless your vendor backported the fix
8.4.27     fixed upstream (>= 8.4.27)
8.1.31     END OF LIFE: no upstream fix; needs vendor backport or upgrade
```

## What the two flaws do

Both bugs leave PHP's internal request state inconsistent and let later code trust it.

- **CVE-2026-109618, "RCE via OOM corruption".** The CVE record says PHP "uses longjmp() for out-of-memory (OOM) errors to exit the current context". Some code paths "leave request memory in an uninitialized state before performing an allocation", and "the subsequent request cleanup procedure may read or branch on this memory." An attacker who can push a request into an out-of-memory failure at the right moment can trigger it.
- **CVE-2026-109619, "RCE via stale global state".** Global state that "temporarily points into request memory" may not be reset, so it "may refer to request memory even after it has been freed." PHP's advisory explains the consequence: "A later request handled by the same worker may use that stale state before normal initialization resets it."

Both carry a CVSS v4.0 base score of 9.2 (`AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H`): network-reachable, no privileges, no user interaction, but high attack complexity with attack requirements present. If you want to decode the vector, see our guide to [reading a CVSS v4.0 vector string](/posts/how-to-read-a-cvss-v4-0-vector-string-metric-by-metric-with-real-cve-records/). The fix shipped in all four branches as one change, described in PHP's NEWS file as "Avoid state corruption via bailout".

Credits in the CVE records name Wiz, Ryan at Calif.io and OpenAI as reporters or finders.

## Exploitation status

The public picture is mixed, so here is what each source says:

| Date | Source | What it says |
|---|---|---|
| Oct 17 | Amazon Threat Intelligence, as reported by Infosecurity Magazine | An exploitation attempt against its MadPot honeypot "dating October 17", four days before disclosure |
| Oct 21 | PHP advisory | A demonstrated exploit against mod_php; patches released |
| Oct 21 | oss-security disclosure | "a complete FPM exploit has not been demonstrated", though source analysis suggests FPM is susceptible |
| Oct 21 | VulnCheck | Scanning with a `php2shell-scan/109618` user agent, and one attempt that "tried to (unsuccessfully) drop a webshell via a server-side session file" |
| Oct 23 | Security Affairs, citing honeypot operators | "no successful remote code execution has been confirmed in real-world attacks" |
| Oct 23 | FBI IC3 public service announcement | Updates "should be applied immediately" |
| Oct 26 | CISA KEV | Both CVEs added; due October 29; forensic triage required for federal agencies |

CISA's Vulnrichment SSVC entry in the CVE records, dated October 21, still says `Exploitation: none`. That predates the KEV listing. For how these signals usually relate, see [CVSS vs EPSS vs KEV](/posts/cvss-vs-epss-vs-kev-which-signal-should-decide-what-you-patch-first/).

Our reading: mass scanning started within hours, working exploits exist, and CISA has listed both as exploited. Whether specific attacks succeeded against production servers is not yet established in public sources. That uncertainty is a reason to hunt after patching, not a reason to wait.

## What to do now

1. **Inventory.** Find every PHP runtime that serves HTTP: VMs, containers, base images, appliances with embedded PHP, and managed hosting. Container images need a rebuild and redeploy; patching the host does nothing for them.
2. **Update.** Move to 8.2.35, 8.3.36, 8.4.27, 8.5.12 or your vendor's patched package. For 8.1 and older, use a vendor backport or upgrade. PHP 8.2 itself reaches end of life on December 31, 2026, according to PHP's release notes, so plan that upgrade too.
3. **Restart every worker.** CVE-2026-109619 is about state that persists across requests in the same worker. Restart PHP-FPM pools, Apache (for mod_php) and any long-running PHP servers after the package update.
4. **Prioritise internet-facing mod_php**, then FPM behind public web servers, then internal applications.

### If you cannot update today

PHP lists stopgaps and is explicit that "only an update is a complete solution" and these "do not make an installation safe":

```ini
; php.ini or FPM pool config, applied before request parsing, then restart workers.
; Illustrative: check each value against your application's needs.

; CVE-2026-109618 (OOM corruption)
; In an FPM pool use php_admin_value[memory_limit] = -1 so applications can't override it.
memory_limit = -1
; 8M if the app takes no uploads, 32M if it needs them; keep upload_max_filesize below it
post_max_size = 8M
upload_max_filesize = 2M

; CVE-2026-109619 (stale global state)
session.upload_progress.enabled = 0
; PHP 8.5 only:
; fatal_error_backtraces = 0
```

The reasoning behind each, from the advisory:

- `memory_limit=-1` "removes the controllable PHP memory limit failure, but an underlying allocation failure can still reach the vulnerable path." With no PHP memory limit, a container or cgroup memory limit becomes your availability boundary. PHP warns: "Do not substitute `RLIMIT_AS` or `RLIMIT_DATA`, as these can cause the vulnerable allocation failure."
- Low `post_max_size`, plus limits at the web server or proxy on decoded request size, field count, multipart part count, header count and nesting depth. These "must also cover requests without a usable `Content-Length`."
- `session.upload_progress.enabled=0` "blocks the confirmed session paths but not other variants". Set it in `php.ini`, the FPM pool or server config; PHP says "Do not rely on `ini_set()` or FPM `.user.ini`."
- Hiding errors does not help: "Hiding diagnostics with `error_reporting`, `display_errors` or `@` does not help."

`php_admin_value` matters here because, per the PHP-FPM documentation, "Settings defined with php_admin_value and php_admin_flag cannot be overridden with ini_set."

## What to hunt for after patching

Patching removes the bug, not an attacker who already used it. Preserve web server and PHP logs before you rotate or rebuild anything. The indicators below come from VulnCheck's published honeypot observations. They describe scanners and one attempt; real attackers can change every one of them.

- **User agents:** `php2shell-scan/109618`, `php2shell-verify/1.0`, `Mozilla/5.0 (php2shell-poc)`.
- **Requests:** multipart POSTs to `/index.php` that upload two files named `a` and `b` through the upload-progress path; follow-up `GET` requests using `php://filter` to read a session file.
- **Session files containing PHP code.** The attempt VulnCheck saw tried to plant a webshell through a session file, with a payload that prints `PWNED::`. A legitimate PHP session file contains serialized data, never `<?php`.

Two checks you can run on a Linux host. We tested both against sample files; adjust paths to your log format and to the `session.save_path` of the pool that serves traffic (`php -i` shows the CLI's value, not necessarily FPM's):

```bash
# Web logs: known scanner user agents and php://filter reads
grep -hE 'php2shell|php://filter' /var/log/nginx/access.log* /var/log/apache2/access.log* 2>/dev/null

# Session files that contain PHP code or the test marker
grep -lE '<\?php|PWNED::' /var/lib/php/sessions/sess_* 2>/dev/null
```

Then do the usual post-compromise checks for a web server: new or changed `.php` files under the document root since October 17, unexpected child processes of the PHP worker or web server user (shells, `curl`, `wget`), and outbound connections from web hosts. Our guide to [logging for incidents](/posts/logging-for-incidents-not-for-dashboards/) covers which of these you will wish you had recorded.

Federal agencies have to follow CISA's forensic triage requirements for this KEV entry. If you want to borrow that process, our explainer on [CISA BOD 26-04](/posts/cisa-bod-26-04-explained-kev-deadlines-forensic-triage-and-what-private-teams-can-borrow/) covers it.

## Limits of this article

We have not read the full GitHub security advisories, which PHP says contain the technical details; they were not reachable from our research environment. Exploitation reporting comes from vendors and press summaries we cite, not from our own telemetry. The hunting indicators come from one vendor's honeypots and will not catch a modified attack. Exposure counts published by vendors differ widely, so we have not repeated them.

## Sources and verification

| Important claim | Source | Status |
|---|---|---|
| Affected ranges 8.2 < 8.2.35, 8.3 < 8.3.36, 8.4 < 8.4.27, 8.5 < 8.5.12; mechanisms; CVSS v4.0 9.2 vector; CWEs; credits | [CVE-2026-109618](https://github.com/CVEProject/cvelistV5/blob/main/cves/2026/109xxx/CVE-2026-109618.json) and [CVE-2026-109619](https://github.com/CVEProject/cvelistV5/blob/main/cves/2026/109xxx/CVE-2026-109619.json) records (PHP CNA) | Verified |
| SAPIs at risk, mod_php highest, fixed releases, 8.1-and-older guidance, source backports, all stopgaps and their caveats | [PHP security advisory, Oct 21, 2026](https://www.php.net/archive/2026.php) | Verified |
| Fix shipped in 8.2.35, 8.3.36, 8.4.27, 8.5.12 as "Avoid state corruption via bailout" | PHP NEWS files for [8.4.27](https://github.com/php/php-src/blob/php-8.4.27/NEWS) and the other tags | Verified |
| Full FPM exploit not demonstrated at disclosure | [oss-security, Oct 21, 2026](https://openwall.com/lists/oss-security/2026/10/21/6) | Verified |
| KEV addition Oct 26, due Oct 29, forensic triage flag | [CISA KEV catalog data](https://github.com/cisagov/kev-data) | Verified |
| Ubuntu 24.04 package 8.3.6-0ubuntu0.24.04.13 includes the fix | Package changelog on an Ubuntu 24.04 host, inspected October 27, 2026 | Verified (one package) |
| php_admin_value cannot be overridden with ini_set | [PHP-FPM configuration docs](https://www.php.net/manual/en/install.fpm.configuration.php) | Verified |
| Exploitation attempt from Oct 17 | Amazon, as reported by [Infosecurity Magazine](https://infosecurity-magazine.com/news/php2shell-exploitation-attempt) | Qualified (secondary report) |
| Scanner user agents, request pattern, session-file webshell attempt | [VulnCheck, Oct 21, 2026](https://www.vulncheck.com/blog/php2shell-vulnerabilities) | Qualified (one vendor's honeypots) |
| No confirmed successful RCE as of Oct 23 | [Security Affairs](https://securityaffairs.com/?p=201538) | Qualified (secondary report) |
| FBI: apply updates immediately | [FBI IC3 PSA I-102326-PSA](https://www.ic3.gov/PSA/2026/PSA261023) | Verified |

## Frequently asked questions

### Which PHP versions fix CVE-2026-109618 and CVE-2026-109619?

PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12, or any later release on the same branch. PHP 8.6.0 RC4 also contains the fix. PHP 8.1 and older are end of life and get no upstream release, though the PHP security team published minimal source backports for 7.4, 8.0 and 8.1.

### My server says PHP 8.3.6. Am I vulnerable?

Not necessarily. Distribution packages backport security fixes without changing the upstream version number. Ubuntu's 8.3.6-0ubuntu0.24.04.13 package, for example, carries a patch named CVE-2026-109618_109619.patch. Check your package changelog for the CVE IDs instead of comparing version strings.

### Is PHP CLI affected?

PHP's advisory names the web-serving SAPIs (PHP-FPM, mod_php, php-cgi, FrankenPHP and LiteSpeed) and rates mod_php as highest risk. It does not single out the CLI. The CLI binary usually comes from the same package, so updating the package covers both.

### Is PHP2Shell being exploited?

CISA added both CVEs to its Known Exploited Vulnerabilities catalog on October 26, 2026. Amazon reported exploitation attempts against its honeypots starting October 17, before disclosure. As of October 23, security firms running honeypots said no successful remote code execution had been confirmed in real-world attacks. Treat it as exploited and patch.


Image credit: Photo by [Compagnons](https://unsplash.com/photos/D7Fjd1-Jkbc) on Unsplash
