October 22, 2026
Deep Dive: Anatomy of the PHP Unauthenticated RCE Vulnerabilities (CVE-2026–109618 &…
PHP remains the backbone of the modern web, powering over 75% of all known websites. When a vulnerability strikes the core engine, the…

By jaeson Bernardsha
3 min read
PHP remains the backbone of the modern web, powering over 75% of all known websites. When a vulnerability strikes the core engine, the blast radius is massive.
Recently, the the PHP Foundation disclosed two critical vulnerabilities, CVE-2026–109618 and CVE-2026–109619, that expose PHP deployments to unauthenticated Remote Code Execution (RCE). Assigned a CVSS v4.0 score of 9.2, these flaws (unofficially circulating as "PHP2Shell") are memory-safety bugs deeply rooted in how the Zend Engine handles Out-of-Memory (OOM) conditions and worker process states.
In this article, I will speak about the technical mechanics of these vulnerabilities, how attackers are manipulating memory states to execute arbitrary code, and the architectural mitigations required to defend your infrastructure.
The Core Problem: Memory Management and Worker State
To understand these vulnerabilities, we first need to look at how PHP processes requests. In modern deployments (like PHP-FPM or Apache mod_php), PHP utilises a persistent worker pool. Instead of spinning up a new process from scratch for every HTTP request, a worker process handles a request, cleans up its memory state, and then stands by for the next request.
This model is highly efficient, but it relies on a guarantee: request teardown must perfectly sanitise the internal state before the worker accepts a new request.
Both CVE-2026–109618 and CVE-2026–109619 break this guarantee by abusing Out-of-Memory (OOM) exceptions.
CVE-2026–109618: The Uninitialized Data Trap
During the lifecycle of a PHP request, the engine allocates memory and initialises internal structures (like the symbol table, request globals, and object handlers).
If an attacker intentionally forces the PHP worker to hit its memory_limit exactly during this initialisation phase, PHP throws a fatal OOM error and immediately jumps to the request cleanup routine (shutdown sequence).
The Vulnerability: The cleanup routine assumes that the internal request data was fully and properly initialised. Because the OOM interruption happened mid-initialisation, the engine attempts to clean up partially initialised, invalid data structures as if they were valid. This improper teardown causes memory corruption within the Zend Engine's allocator (ZendMM), leaving dangling pointers that can be manipulated to control execution flow.
CVE-2026–109619: Stale State and Memory Reuse
This second vulnerability is fundamentally a state-leakage issue that behaves similarly to a Use-After-Free (UAF) bug across request boundaries.
When a request finishes (or crashes via OOM), the backing memory for that request is freed by the memory manager. However, under specific edge cases tied to OOM handling, the internal state pointers owned by that request survive the teardown process.
The Vulnerability: Because the worker process does not die, it picks up the next HTTP request in the queue. Before the normal initialisation sequence can completely reset the worker's environment, the engine attempts to utilise the stale state left over from the previous request. Since the backing memory for that state has already been freed (and potentially reallocated with attacker-controlled data from the new request), the engine ends up executing against corrupted memory structures.
The Exploitation Vector (PHP2Shell)
To exploit these vulnerabilities, an attacker does not need authentication. They only need to be able to send HTTP requests to the target server.
The exploitation chain looks like this:
- Triggering the OOM: The attacker sends an HTTP request containing an abnormally large payload (e.g., a massive POST body or heavily nested multipart/form-data) designed to intentionally exhaust the
memory_limitdefined inphp.ini. - Timing the Interruption: By carefully crafting the payload's size and structure, the attacker forces the OOM exception to trigger precisely when the Zend Engine allocates request-bound state structures.
- Corrupting the Heap: The interrupted initialisation (CVE-2026–109618) or the surviving stale state (CVE-2026–109619) corrupts the worker's heap.
- Hijacking the Next Request: The attacker immediately sends a second, highly specific HTTP request to the same worker process. This request contains the actual malicious payload (shellcode or a ROP chain) which is mapped into the memory space previously freed by the OOM crash.
- Execution: When the PHP worker attempts to process the new request using the stale, now attacker-controlled pointers, it jumps to the attacker's payload, resulting in a full system compromise.
Remediation & Architectural Defense
The impact of these flaws spans from PHP 5.4 all the way through 8.5.11. Because the vulnerability lives in the core memory allocator, it affects almost all deployment architectures (PHP-FPM, Apache mod_php, Nginx FastCGI, etc.).
1. Immediate Patching (The Only True Fix)
The PHP Foundation has released patched binaries that harden the request teardown sequence and ensure memory state is forcefully zeroed out even during OOM crashes.
- Upgrade to:
8.5.12,8.4.27,8.3.36, or8.2.35. - Note: If you are running PHP 8.1 or older, you are on an End-of-Life (EOL) version and will not receive patches. You must migrate to a supported branch immediately.
2. Temporary Mitigations (WAF and Reverse Proxy Limits)
If you cannot patch immediately, your goal must be to prevent the attacker from triggering the OOM condition. You can achieve this by dropping excessively large requests at the network edge, before they ever reach the PHP daemon.
- Nginx: Enforce a strict
client_max_body_sizein yournginx.conf. - Apache: Use the
LimitRequestBodydirective. - WAF Rules: Deploy Web Application Firewall rules to block requests with unusually large Content-Length headers, deeply nested JSON, or anomalous multipart form boundaries.
Warning: Lowering the memory_limit in php.ini will not fix this. In fact, lowering it makes the OOM condition easier for an attacker to trigger with smaller payloads. The defence must happen at the reverse proxy or WAF layer.
Conclusion
CVE-2026–109618 and CVE-2026–109619 are stark reminders that memory safety is not just a problem for compiled binaries like C/C++ applications; the underlying engines of our interpreted languages are just as susceptible. Patch your environments, audit your legacy systems, and ensure your edge defences are dropping anomalous request sizes.