On 21 October 2026 the PHP project released an emergency fix for two critical, unauthenticated remote-code-execution bugs in its core engine, disclosed together under the nickname PHP2Shell. This article covers the first of the pair, CVE-2026-109618, “RCE via OOM corruption.” Its sibling, CVE-2026-109619, “RCE via stale global state,” has its own write-up, and the two share a scope and a fix.
Like its sibling it is rated CVSS v4.0 9.2 (Critical), and it was announced by Jakub Zelenka for the PHP security team on the oss-security mailing list at 16:41 CEST on 21 October. The full technical write-up is GitHub Security Advisory GHSA-w8hw-w9fx-j79w.
The one-sentence version
From the PHP security team’s announcement:
“PHP uses longjmp() to abort request handling on out-of-memory (OOM) errors. An allocation failure can interrupt initialization while incomplete request state is already reachable. Request shutdown may then access this invalid state, potentially allowing remote code execution.” (Jakub Zelenka, PHP security team, oss-security, 21 Oct 2026)
Where CVE-2026-109619 is about a pointer that lives too long and crosses into the next request, CVE-2026-109618 stays inside a single request. Running out of memory makes PHP jump out of a half-finished operation, and it then cleans up as if that operation had completed.
The mechanism: a jump over a half-built object
To keep its own memory use bounded, PHP enforces a memory_limit. When an allocation would cross it, or when the underlying system allocator genuinely fails, PHP has historically bailed out of the current operation with the C primitive longjmp(), a non-local jump that unwinds straight back to a saved recovery point.
The problem is when that jump can fire. PHP builds internal data structures step by step. It will, for instance, update a container’s bookkeeping (counters, metadata) and then allocate the storage that the bookkeeping describes. If the allocation in the middle of that sequence fails, longjmp() leaps out after the metadata was updated but before the object was finished. The structure now claims to hold something that was never actually initialized.
PHP’s per-request shutdown then runs, and in some servers it runs unconditionally, even when request start-up failed. Shutdown walks the structure, trusts the metadata, and operates on memory that is not what the metadata says it is. That is the “OOM corruption”: a cleanup routine acting on a half-built object.
The weakness classes the advisory assigns capture this precisely: CWE-755 (improper handling of exceptional conditions), CWE-824 (access of an uninitialized pointer), and CWE-1325 and CWE-1419 (improperly controlled sequential allocation and incorrect initialization of a resource).
Why it fires before your code runs
The reason this is rated so highly is timing. PHP parses the incoming request body, including multipart/form-data and URL-encoded form fields, during request start-up, before a single line of your application runs. An attacker who can make that early parsing exhaust memory triggers the whole sequence pre-authentication.
The advisory catalogs several ways a request that looks within limits can still blow past memory_limit, because PHP’s in-memory representation of parsed input can be far larger than the bytes on the wire. The upshot, in the words of Datadog’s independent reproduction, which triggered the corruption on PHP 8.5.11 with a single unauthenticated POST, is that “nothing in the target script can impact or defend against the exploit (authentication, filtering…).”
Which servers are affected
The PHP team is clear that this is engine-level, but the severity depends on the server module (the SAPI) that connects PHP to the web server, because each one treats a failed start-up differently.
- Apache
mod_phpis the highest risk and the confirmed RCE. It “unconditionally invokes the request shutdown procedure, even when startup fails.” Automatic body parsing during start-up can exhaust the limit, and shutdown then processes the invalid state before any application code runs. The advisory reports RCE over HTTP with default limits, including multi-worker prefork setups. - PHP-FPM is partly susceptible. FPM exits the child when start-up fails, which prevents consumption of the invalid state in that window. An out-of-memory error after a successful start-up may still reach the issue, but no complete FPM exploit was demonstrated for this CVE.
- FrankenPHP and LSAPI are likely but unvalidated. Source analysis suggests FrankenPHP is susceptible, since it calls shutdown unconditionally, and LSAPI is modeled on FPM.
The PHP release summary names the full at-risk set as “all PHP installations serving web requests, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed,” and repeats that the risk is highest for mod_php.
How far it reaches
CVE-2026-109618 shares its scope with its sibling, which is to say most of the web.
- Reach. PHP powers around 70 percent of all websites (Wiz), or 69.3 percent of sites whose server-side language is known (W3Techs, via Tenable).
- Version range. Fixed in 8.2.35, 8.3.36, 8.4.27 and 8.5.12, but affected code reaches back to PHP 5.4.0 according to Calif.io.
- Exposure. Palo Alto Cortex Xpanse counted “over 22.6 million exposed instances potentially vulnerable” to the pair (Unit 42). Host-level estimates range from 1.3 million (Silas Cutler) to 1.9 million (Shodan, Henk Poley), via Tenable.
What makes it more or less dangerous
What raises the risk:
mod_phpand default limits. The demonstrated exploit runs before application code, and PHP’s default memory limits are enough. As Datadog notes, “PHP’s default memory limits are vulnerable.”- Pre-disclosure exploitation. Amazon Threat Intelligence logged an attempt on 17 October 2026, four days before the patch, and reports broad exploitation since (via Tenable). watchTowr says it “observed exploitation of both CVE-2026-109618 and CVE-2026-109619 in the wild.” Unit 42 noted that at least one European government took its site offline as a precaution.
- AI lowers the cost of a working exploit. Reliable exploitation requires sizing a request to fail at exactly the right moment and defeating ASLR, and researchers describe current models as collapsing the per-target tuning effort that used to make this impractical.
What lowers the risk:
- Reliability is genuinely hard. An attacker has to force the allocation to fail at a precise point and locate valid memory addresses under ASLR. Rapid7 found public proof-of-concept code to be target-specific, with “none” that “appears broadly reliable,” and PHP “did not identify any functional exploits at the time of release.” This is a window to patch, not an all-clear.
- FPM’s fail-fast behavior. Exiting the child on start-up failure closes the most direct, application-independent path.
The fix, and the one config change that is not a fix
The patch removes longjmp() from out-of-memory handling and replaces it with a two-tier scheme.
A soft limit defers the out-of-memory error until PHP reaches a safe point, letting an in-progress operation finish initializing its data before the error is raised. A hard limit, at a higher threshold, terminates the worker immediately with _exit(137) instead of running normal cleanup over possibly invalid state.
Datadog’s analysis adds a sober caveat: the underlying pattern of “updating metadata before allocating the memory it describes” still exists in places, so “we expect more of these bugs to surface.” The engine-level fix closes the known cases. It does not refactor the whole pattern away.
Update to a patched release:
| Branch | Fixed version |
|---|---|
| PHP 8.5.x | 8.5.12 |
| PHP 8.4.x | 8.4.27 |
| PHP 8.3.x | 8.3.36 |
| PHP 8.2.x | 8.2.35 |
| PHP 7.4 to 8.1 | No official release; the security team published minimal source backports |
| PHP 5.4 to 7.3 | End of life, so upgrade to a supported branch |
Restart every worker after updating, and verify the version serving web requests, not the CLI binary.
The widely shared stop-gap for this specific CVE is memory_limit=-1, applied so that applications cannot override it, for example through php_admin_value in the FPM pool or Apache config. The advisory is candid about why that is only partial: “This removes the controllable PHP memory limit failure, but an underlying allocation failure can still reach the vulnerable path.” The release notes are blunter still: “There are no complete mitigations, updating is the only safe choice.” One more sharp edge from the advisory: do not use RLIMIT_AS or RLIMIT_DATA to bound memory, since they make mmap() fail and can trigger the vulnerable path.
What to look for
Datadog recommends correlating signals at three layers: large or unusual form submissions, memory-exhaustion errors during request initialization, and unexpected shell processes spawned by web workers. A successful exploit “doesn’t necessarily crash the worker or return an error,” and one refined demonstration returned HTTP 200 while the same worker kept serving, so a clean access log is not evidence of safety. Controls at a reverse proxy in front of PHP, capping decoded request size, field and part counts, and nesting depth, can block malicious requests before they reach the vulnerable parser, though PHP stresses these reduce exposure rather than close the hole.
In short
CVE-2026-109618 is what happens when an error-handling shortcut, a longjmp() straight out of a failed allocation, meets a cleanup routine that trusts half-finished bookkeeping, all during the request start-up window that runs before your code. The scale is the story: a decade of PHP releases, roughly 70 percent of the web, and millions of exposed hosts. The response is the same two sentences as for its sibling. Patch to a fixed version, restart your workers, and confirm the version that serves your traffic.
Primary sources
- PHP security team, oss-security announcement, CVE-2026-109618, 21 Oct 2026, 16:41 CEST
- GitHub Security Advisory GHSA-w8hw-w9fx-j79w (CVE-2026-109618)
- php.net, Security advisory: Critical remote code execution vulnerabilities, 21 Oct 2026
- MITRE CVE-2026-109618, NVD entry
- Wiz Research, PHP2Shell, 21 Oct 2026
- Datadog Security Labs, php2shell: critical vulnerabilities in PHP, 21 Oct 2026 (Nick Frichette, Emile Spir, Eslam Salem)
- Tenable, php2shell FAQ (Satnam Narang)
- Unit 42 (Palo Alto Networks), Threat Brief, 21 Oct 2026
- Rapid7, Emergent Threat Response, 21 to 22 Oct 2026
- Google Cloud, Responding to core PHP vulnerabilities, 21 Oct 2026 (Chris Betz, Raluca Ada Popa)
Companion article: CVE-2026-109619, RCE via stale global state.