On October 21, 2026, the PHP foundation released a security advisory and emergency patches addressing two core runtime vulnerabilities responsible for permitting unauthenticated remote code execution (RCE). PHP identified the following modules as critically exploitable, requiring immediate attention: mod_php, PHP-FPM, php-cgi, FrankenPHP and LiteSpeed.
An estimated 70% of all websites run on PHP-powered Content Management Systems such as WordPress, Joomla, Drupal, and several others. Last week, ThreatLocker clarified that PHP advised the only solution to these vulnerabilities is an immediate patch while offering temporary mitigation solutions in the event that a full patch isn't available.

Affected PHP versions

Technical analysis of PHP2Shell vulnerabilities
CVE-2026-109618
PHP's handling of memory-allocation failures can allow a remote, unauthenticated attacker to execute code on a vulnerable web server. The issue occurs when PHP encounters an out-of-memory (OOM) error during request processing, exits the current operation before internal data has been safely reset, and later attempts to use that invalid data.
The reading and writing of this data can be loosely controlled by different techniques, leading to execution of attacker commands.
Use After Free
Looking deeper into this functionality, PHP is written in C and uses the longjmp() C function to abandon request processing on memory allocation failure. longjmp() brings the execution point to an earlier defined “jump” point in the code, which in this case bypasses the normal control flow and crucial cleanup functions.
Due to these cleanup functions being skipped, reachable request memory is left incompletely initialized and unsafe. This is broader than a single dangling upload counter.
A session feature upload_progress is built into PHP’s Sessions extension and can be invoked in the upload process within the POST form. The order of operations that is taken on this request is what allows a Use After Free vulnerability to be exploited.
When a multipart upload request is received by PHP, the upload-progress field is recognized and pointers to the request’s heap, id and http_session_vars, are temporarily used for handling the request during this setup phase.
Normally, after the upload parts are parsed, PHP modules are initialized, and these module global pointers are reset to safe values. If the request processing is interrupted before initialization resets them, the request heap they point to is destroyed, and longjmp() exits the function. The now dangling pointers are left referring to freed memory.
This memory-handling flaw is taken advantage of through multipart upload POST requests. PHP limits the size of a multipart upload through the post_max_size variable which is incremented based on the Content-Length of the request.
However, on multipart upload, several request headers and form fields are also created that do not increment this variable. By creating a multipart upload with hundreds of empty parts, this memory space can be flooded with headers and form fields while never incrementing the protecting counter post_max_size. This leads to a function-level memory failure, destruction of the request heap, and invocation of longjmp() without cleaning up the temporary pointers.
Nested field names in the request, for example in the query string, multiply the creation of headers and form fields for a single request. The temporary pointers id and http_request_vars are now considered dangling pointers, since the memory space they refer to has been freed.
The following multipart request now follows the dangling pointer id and sees existing data. Since the previous heap was freed/destroyed, this memory region does not contain the session ID and instead contains some other data outside of the request’s memory. This value is sent back to the user as a response cookie PHPSESSID, providing a process-memory disclosure.
This disclosure provides the attacker with a glimpse of the ASLR-mapped memory outside of the current request heap. Several of these disclosures on a single worker process can reveal enough mapped memory to continue to the final step of memory corruption and remote code execution.
Command injection
PHP’s generic deserializer uses a destructor function as part of standard request cleanup to unserialize and destroy any request-specific variables. This deserializer happens to suffer the same memory flaw as multipart uploads.
When PHP receives an attacker request, the request contents are written to memory and abandoned as the memory fault occurs. These contents may contain a forged data structure with its own destructor function and PHP arguments for later execution, which are all interpreted as strings.
As the next request is processed, that stale memory is reclaimed and interpreted as a valid structure. The destructor function now points to zif_system, PHP’s own implementation of the system() function. Cleanup of this request calls the destructor function, invoking zif_system with attacker-defined arguments, leading to remote code execution.
The command injection lifecycle is as follows:
- Request A is made containing a forged structure and PHP arguments
- A fatal memory error creates stale pointers to the forged structure
- Request B reclaims the forged structure as valid
- Request cleanup calls the forged structure’s destructor function
- The destructor function invokes
zif_systemproviding RCE
The confirmed exploitation path through Apache’s mod_php module survives startup failure into request shutdown making it the most susceptible to this CVE. PHP-FPM instead exits a worker after a failed startup, preventing that exact path. PHP’s OOM advisory treats post-startup FPM exposure as supported by source analysis but also does not claim a complete demonstrated FPM exploit exists for this CVE. FrankenPHP and LSAPI conclusions likewise require attention to the stated evidence level.
PHP's temporary mitigation
If you cannot update immediately
While an update is the only complete solution, the following measures reduce exposure to specific attack paths but do not make an outdated installation safe.
RCE via OOM corruption (CVE-2026-109618):
- Set
memory_limit=-1, preferably in a way applications can't override, such asphp_admin_valuein theFPMpool or Apache configuration, and check that no pool, directory or application setting puts a finite limit back. This removes the controllable PHP memory limit failure, but an underlying allocation failure can still reach the vulnerable path. - Set a low
post_max_size. For applications that don't require file uploads, setpost_max_size = 8M. If file uploads are necessary, setpost_max_size = 32M. Keepupload_max_filesizebelowpost_max_size. Consider enforcing limits at the web server or proxy level for decoded request size, input field count, multipart part count, header count, and nesting depth. These limits must also cover requests without a usableContent-Length. - Use a container or
cgrouplimit as an availability boundary, preferably with a policy that kills only the affected worker. Do not substituteRLIMIT_ASorRLIMIT_DATA, as these can cause the vulnerable allocation failure.
CVE-2026-109619
CVE-2026-109619 allows for persistent global variables to outlive request allocations allowing a worker to retain references to areas of the heap responsible for requests.
When a fatal OOM error is encountered before reinitialization as shown before, a global backtrace is created to hold that information, and the request heap is destroyed without a proper cleanup, leaving that backtrace intact. Affected versions of PHP allow the worker to survive this error and process the next request.
On this next request, if the worker suffers the same error, it can access the existing backtrace before it is cleared in reinitialization, effectively reclaiming stale memory. Carefully sized requests can write attacker-controlled bytes to that same stale memory, causing the worker to interpret those bytes as internal instructions, leading directly to RCE.
PHP's oss-security announcement explicitly confirms unauthenticated RCE against mod_php and FPM, subject to state, configuration and application behavior.
Several stale state consumers have been identified: session upload progress handling, PHP 8.5's fatal error backtrace, and in PHP-FPM, the generic unserializer.
Providing multiple workers to process requests reduces success per attempt but does not eliminate the condition. A dangling pointer still identifies a location, which may be returned to the attacker, written to directly, and falsely interpreted as internal instructions.
- Request A publishes request owned state in a persistent worker field
- An interruption or shutdown ordering leaves the field populated
- Request allocations are released
- Request B reaches the SAME worker
- Early processing consumes the old reference before its normal reset
- Attacker controlled bytes are executed
PHP's temporary mitigation
If you cannot update immediately
While an update is the only complete solution, the following measures reduce exposure to specific attack paths but do not make an installation safe.
RCE via stale global state (CVE-2026-109619):
- Set
session.upload_progress.enabled=0and restart every worker. Usephp.ini, anFPMpool or server configuration that applies before request parsing. Do not rely onini_set()orFPM .user.ini. This blocks the confirmed session paths but not other variants. - On PHP 8.5, set
fatal_error_backtraces=0and restart every worker. This blocks the confirmed fatal backtrace path only. - Remove invalid or deprecated settings applied per request that emit diagnostics before initialization. Hiding diagnostics with
error_reporting,display_errorsor@does not help. - Fix attacker-reachable fatal errors and execution timeouts, including failures in callbacks, upload or import processing and cleanup.
Conclusion
PHP2shell highlights the serious risk posed by CVE-2026-109618 and CVE-2026-109618, a vulnerability that may allow remote attackers to execute code on vulnerable PHP servers by triggering memory exhaustion during request processing.
Successful exploitation could compromise the affected web application and provide access to sensitive data or systems accessible to the web server.
Organizations should prioritize upgrading to a patched PHP release, assess their exposure based on their deployment configuration, and apply appropriate safeguards while remediation is underway. Configuration-based mitigations may reduce risk but should not be considered a substitute for patching.
Behavioral IOCs
HTTP/WAF logs
- Unexpected multipart POST requests
Content-Type: multipart/form-data
- Nested parameter names
- Any form field containing i.e.
a0[b0][b1][b2]…
- Any form field containing i.e.
- Form fields containing PHP opening tags or command execution expressions
Content-Disposition: form-data; filename=“<?php system(‘id’); ?>”
- HTTP responses with abnormally large PHPSESSID cookies
- May contain URL encoded or PHP-like data
Set-Cookie: PHPSESSID=%00%00%00%00%F0%9F%8B%7F%00;
PHP logs
- PHP memory exhaustion
Allowed memory size exhausted
- Fatal errors before application initiation
In Unknown on line 0
- Worker crashes or instability
- Multipart request timeouts
- Sharp increases in memory/CPU usage of worker process
Host-based indicators
- PHP worker spawning a shell or command interpreter
- PHP spawning curl or wget
- New or modified executable PHP files in upload directories or web roots


