Oct 23, 2026·6 min read·10 visits
Unauthenticated remote code execution vulnerability in persistent PHP worker processes caused by stale global pointers retained after out-of-memory longjmp bailouts.
CVE-2026-109619 (PHP2Shell) is a critical Use-After-Free vulnerability in the core PHP engine caused by improper global state cleanup during out-of-memory exception handling across persistent worker requests.
CVE-2026-109619, tracked alongside CVE-2026-109618 and collectively designated as PHP2Shell, represents a high-severity engine-level flaw in the core PHP runtime (php-src). The vulnerability affects multi-request PHP execution environments such as PHP-FPM worker pools and Apache mod_php modules, where long-lived worker processes handle multiple HTTP requests sequentially.
The underlying weakness resides in how the Zend Engine manages global compilation and execution state during abnormal request termination. When exceptional conditions occur—specifically Out-Of-Memory (OOM) events triggered during execution—the engine fails to clear or improperly repopulates pointers targeting request-allocated memory pages. This leaves dangling global pointers across worker lifecycle boundaries.
An unauthenticated remote attacker can exploit this condition by forcing an OOM state in a primary HTTP request and subsequently issuing a secondary request handled by the same worker thread. Memory allocation during the second request overwrites the freed memory structure, enabling arbitrary code execution through corrupted engine function pointers or Zend object structures.
The root cause stems from the interaction between Zend Memory Manager (ZMM) request-scoped allocations and long-lived executor globals (executor_globals and compiler_globals). PHP uses emalloc() for per-request memory allocation, which is automatically freed in bulk at request termination via zend_arena or ZMM pool resets.
When memory allocation fails during complex operations such as parsing large multipart uploads, nested array processing, or string operations, the Zend Engine invokes zend_bailout(). This mechanism relies on C standard library setjmp() and longjmp() functions to unroll the call stack and transfer control directly to the request shutdown handling routine.
Because longjmp() bypasses standard scope cleanup and object destructors, global state pointers—including fallible interned string fallbacks, error backtrace buffers, and delayed OOM metadata structures (EG(delayed_oom))—retain raw memory addresses allocated in the aborted request context. Upon request deactivation, these pointers remain uncleared or are repopulated during shutdown execution.
When the persistent worker thread accepts a subsequent HTTP request, internal initialization routines or premature error handlers read from these global pointers prior to full request re-initialization. Because the backing memory page was freed by ZMM, the reads execute against unallocated or reallocated heap memory, resulting in a Use-After-Free (CWE-416) condition.
The primary patch commit (31c0ea7d7ff1d1fccb6492e52dab544011628065) introduced systemic structural changes across the core VM, error handling routines, and extension memory allocation functions. The core fix addresses both the mechanism of stack unrolling and the persistent state lifecycle.
Rather than executing abrupt longjmp() jumps during allocation failure, the patched engine raises UnwindExit exceptions within the Zend VM execution loop. This allows destructors, stack frames, and fiber contexts to execute clean teardowns without abandoning global variables in corrupted states.
// Pre-patch vulnerability path: Immediate setjmp/longjmp context jump
void zend_bailout(void) {
// Bypasses cleanup destructors and leaves global pointers populated
longjmp(EG(bailout), 1);
}
// Post-patch remediation: Controlled unwinding and explicit global state resetting
void compiler_globals_ctor(zend_compiler_globals *compiler_globals) {
// Explicitly reset fallible flags and delayed structs across initialization
compiler_globals->interned_strings_fallible = false;
EG(delayed_oom) = NULL;
}Additionally, core PHP extensions were converted to use fallible memory allocation routines (femalloc, safe_femalloc, and array_finit). These functions return explicit failure indicators (NULL or FAILURE) to caller functions rather than immediately calling zend_bailout(), ensuring structured error handling across memory limits.
Exploitation requires two consecutive HTTP requests directed at the same persistent PHP worker process. The attacker does not require prior authentication or specialized privileges on the target system.
In the initial phase, the attacker submits an HTTP request designed to induce an Out-Of-Memory failure. This is frequently achieved by POSTing large multipart form data, deeply nested array parameters, or payloads triggering high-memory string operations. The OOM condition triggers zend_bailout(), causing the engine to terminate request execution prematurely while leaving stale memory addresses stored inside global structures.
In the secondary phase, the attacker immediately sends a follow-up request to the target worker. By carefully shaping the memory layout of the second request payload (heap grooming), the attacker controls the contents of the freed ZMM chunk. When the Zend Engine accesses the stale global pointer during early request handling, it interprets attacker-controlled heap byte sequences as function pointers or object vtables, yielding execution control flow redirection.
CVE-2026-109619 carries a CVSS v4.0 score of 9.2 (Critical) and a CVSS v3.1 score of 8.1 (High). The primary threat vector is unauthenticated remote code execution with the permissions of the underlying web server process (such as www-data or nginx).
Successful execution grants the attacker full control over the application environment. Impact scope includes unauthorized access to local file systems, reading application configuration secrets, retrieving database credentials, and establishing persistent reverse shells or lateral movement within the network segment.
Process crashes resulting from unsuccessful exploitation attempts cause temporary worker crashes, leading to service degradation or denial of service (DoS). While EPSS scores reflect an initial percentile rank of 93.05%, public availability of proof-of-concept scripts increases risk exposure across unpatched web infrastructure.
The recommended remediation is upgrading the PHP engine to a patched upstream version. Production deployments should update immediately to PHP 8.2.35, 8.3.36, 8.4.27, or 8.5.12 based on their active release branch.
For systems running End-of-Life PHP releases (such as 8.1, 8.0, or 7.x) where official upstream patches are unavailable, organizations must apply vendor-supplied backported patches or implement infrastructure-level defense mechanisms.
Temporary operational mitigations include enforcing strict HTTP body limits at the web server layer (e.g., setting Nginx client_max_body_size 10M or Apache LimitRequestBody 10485760), disabling session upload progress (session.upload_progress.enabled = Off), and setting aggressive worker process recycling limits (e.g., pm.max_requests = 100 in PHP-FPM) to minimize process lifetime.
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
PHP PHP Group | 8.2.0 - 8.2.34 | 8.2.35 |
PHP PHP Group | 8.3.0 - 8.3.35 | 8.3.36 |
PHP PHP Group | 8.4.0 - 8.4.26 | 8.4.27 |
PHP PHP Group | 8.5.0 - 8.5.11 | 8.5.12 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-416 |
| Attack Vector | Network |
| CVSS v4.0 | 9.2 (Critical) |
| EPSS Score | 5.76% (93.05th percentile) |
| Impact | Remote Code Execution |
| Exploit Status | Proof of Concept Available |
| KEV Status | Not Listed |
Referencing memory after it has been freed can cause a program to crash, use unexpected values, or execute arbitrary code.
A heap-based buffer overflow vulnerability in Pillow PyPI binary wheels (versions 11.1.0 to 12.x) allows remote code execution or application crash via crafted JPEG 2000 files processed by the bundled libopenjp2 library.
CVE-2026-109618 (dubbed PHP2Shell) is a critical vulnerability in the PHP engine core resulting from improper out-of-memory exception handling via longjmp(). When request allocation fails mid-processing, non-local control flow bypasses cleanup procedures, leaving memory structures uninitialized or in a use-after-free state during request shutdown.
In Python virtualenv prior to version 21.14.9, activation script generators and configuration writers use Path.exists() before writing files. Because Path.exists() resolves symbolic links, it returns False for dangling symlinks. Consequently, virtualenv skips unlinking pre-planted symbolic links or hard links, writing data directly to target locations outside the intended virtual environment directory.
A remote code execution vulnerability exists in Microsoft .NET due to untrusted data deserialization within the PresentationCore component. The flaw stems from implicit auto-conversion flags during clipboard data retrieval operations.
An out-of-bounds write vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio allows unauthenticated remote attackers to execute arbitrary code via crafted pixel-shader bytecode or auto-converted clipboard payloads.
ASP.NET Core contains a thread deadlock vulnerability (CWE-833) that allows an unauthenticated remote attacker to cause a denial of service over the network by exhausting server thread pool resources.