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:
$ 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
// 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));
}
$ 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. 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.
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
- 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.
- 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.
- 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.
- 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”:
; 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 substituteRLIMIT_ASorRLIMIT_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 usableContent-Length.” session.upload_progress.enabled=0“blocks the confirmed session paths but not other variants”. Set it inphp.ini, the FPM pool or server config; PHP says “Do not rely onini_set()or FPM.user.ini.”- Hiding errors does not help: “Hiding diagnostics with
error_reporting,display_errorsor@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.phpthat upload two files namedaandbthrough the upload-progress path; follow-upGETrequests usingphp://filterto 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):
# 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 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 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 and CVE-2026-109619 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 | 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 and the other tags | Verified |
| Full FPM exploit not demonstrated at disclosure | oss-security, Oct 21, 2026 | Verified |
| KEV addition Oct 26, due Oct 29, forensic triage flag | CISA KEV catalog 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 | Verified |
| Exploitation attempt from Oct 17 | Amazon, as reported by Infosecurity Magazine | Qualified (secondary report) |
| Scanner user agents, request pattern, session-file webshell attempt | VulnCheck, Oct 21, 2026 | Qualified (one vendor’s honeypots) |
| No confirmed successful RCE as of Oct 23 | Security Affairs | Qualified (secondary report) |
| FBI: apply updates immediately | FBI IC3 PSA I-102326-PSA | 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.
Vulnerability ManagementIncident ResponsePhpRemote Code Execution
