Oct 22, 2026
PHP2Shell – Critical Vulnerabilities in PHP Core (CVE-2026-109618/CVE-2026-109619)
Two major CVEs have been discovered in PHP core, both rated critical, leading to server crashes and potential remote code execution on affected web servers.
Two major CVEs have been discovered in PHP core, both rated critical, leading to server crashes and potential remote code execution on affected web servers.
CVE-2026-109618 and CVE-2026-109619 are both ‘use-after-free’ vulnerabilities, found in PHP versions 5.4 and onward. The flaws arise from both memory management and state handling components of PHP core, which causes request data to be improperly freed while still referenced, so a later request can use it.
An unauthenticated attacker can send a series of crafted HTTP requests to trigger a Use-After-Free that can eventually lead to remote code execution.
- CVE ID: CVE-2026-109618
- Severity: Critical
- CVSS Score: 9.2
- EPSS Score: TBC, high likelihood of exploitation
- Impact: Remote Code Execution
- Attack Vector: Network
- Authentication Required: No
- Vulnerable Component: longjmp() function for Out-Of-Memory errors and _zend_hash_str_add_or_update_i() in PHP core versions after v5.4
- CVE ID: CVE-2026-109619
- Severity: Critical
- CVSS Score: 9.2
- EPSS Score: TBC, high likelihood of exploitation
- Impact: Remote Code Execution
- Attack Vector: Network
- Authentication Required: No
- Vulnerable Components: longjmp() function for Out-Of-Memory errors, fatal_error_backtraces and session upload progress components, as well as other state or error handling components, in PHP core versions after v5.4
Both CVEs were initially discovered by Calif, OpenAI, and Wiz. At a high level overview, PHP2Shell exploitation requires the attacker to be able to consistently induce an Out-Of-Memory (OOM) error on the webserver. One way this can be done is through using a specifically crafted HTTP multipart request with no declared Content-Length, and a nested file upload with no filename specified. Since PHP will allocate file metadata arrays even with a file with no data supplied, this will quickly use up PHP’s memory, causing a fatal OOM error.
Now that the attacker has the ability to cause an OOM error, what can they do with it? Once an OOM occurs, PHP will use the zend_bailout() function in Zend, the PHP engine, to immediately stop handling the malformed HTTP request memory region by calling longjmp(), even if other C routines are still processing the memory region. Since other C routines are still processing the memory region, it can potentially lead to the memory region being treated as a valid memory region later on. PHP can then “use” the “freed” memory later on, which can lead to memory disclosure and corruption.
CVE-2026-109618 addresses when this behavior happens in the _zend_hash_str_add_or_update_i() function, a helper function that processes string-key insertion into PHP arrays. If an OOM error occurs when PHP attempts to initialize a zend string into the array, the string is never initialized as PHP calls zend_bailout(), but the internal counters are already incremented before the string initialization, so the PHP array still treats the inserted key as a valid memory region, with the memory contents being whatever was there before the initialization. An attacker can trigger this behavior by submitting a malformed OOM error inducing POST request, as POST request variables are inserted into the $_POST global array. Eventually, when the PHP request fails due to the OOM error, PHP will attempt to clean up the malformed global $_POST array, which ends up cleaning up the invalid memory region as well due to the internal counters still treating this memory region as valid. Part of the cleaning routine includes referencing a function pointer table that is tagged by the invalid memory region, allowing attackers to redirect execution to wherever they wish.
This behavior can also lead to remote memory disclosure, given how PHP handles session data. If an attacker triggers an OOM by submitting a crafted multi-part request while the session state is initializing, it aborts with the session id PS(id) potentially pointing to already freed memory. The attacker can then submit another multi-part HTTP request without a file part, and if the same worker process is handling the request, it will clean up the file upload despite there being no file part in the request. This will cause PHP to also clean up the previous request, URL-encode the heap memory that PS(id)points to into the PHPSESSID cookie value, and return it to the attacker. This heap region may contain memory addresses of the heap, which the attacker can use to bypass ASLR down the line.
CVE-2026-109619 addresses when this behavior affects global states across multiple requests. Normally, global states for a request must reset before the memory is freed, certain input/configuration/memory/session operations run when another request arrives, and the memory is initialized again for the second request. If an OOM error occurs, the PHP global state can abort without the state resetting, again caused by the longjmp() call. When the second request arrives, the input/configuration/memory/session operations can act on the improperly reset state, causing a Use-After-Free.
One way this manifests itself is PHP’s fatal_error_backtraces, which if enabled (the default configuration), causes PHP to keep a backtrace of the most recent fatal error in the global state. The attacker can trigger an OOM error with a crafted HTTP request to poison the global state backtrace with attacker-controlled data. Since the state is never reset, the global state still points to attacker-controlled data. The attacker can then submit a second request, and if the same worker runs a diagnostic on the second request, it will act on the attacker-controlled data on the improperly reset backtrace state, allowing the attacker to manipulate memory as they please.
- For remote exploitation, the web service must use PHP.
- The version of PHP must be 5.4 onwards, and less than 8.2.35, 8.3.36, 8.4.27, 8.5.12.
Since this vulnerability exists before any application code is executed, exploitation attempt detection is tricky. One method is to monitor HTTP multipart requests and ensure the field names and data are expected data. Another way is to search for memory exhaustion messages in the PHP error log, especially ones that mention bytes exhausted in Unknown on line 0, as that indicates that the OOM error happened before PHP executed any application code. However, these errors can also appear legitimately as well, making the above recommendations not a foolproof solution to detect PHP2Shell exploitation.
You can practice exploiting this vulnerability in a controlled environment through the OffSec lab for CVE-2026-109618 in Proving Grounds Play – available for free to the entire community.
- Please note that this lab focuses on the exploitation of CVE-2026-109618 only, and runs PHP 8.4.26 as mod_php under Apache 2.4.69 prefork on Debian 13 (trixie), amd64. The `memory_limit` is lowered from 128M to 8M, `post_max_size` is raised from 8M to 64M, and Apache is restricted to a single worker so successive requests reach the same process. Error display and session upload-progress tracking are enabled, and ASLR remains enabled. The container is pinned to the following image, fixing its bundled library versions:
- php:8.4.26-apache@sha256:60111400ff77bdc44fa79b4f072afe49a42abba71e0846ad496be4761dc9c11a
- These settings support reliable exploitation; they aren’t universal prerequisites for exploiting the vulnerability.
- OffSec’s Proof of Concept exploitation script can be found here:
- Update the PHP version to either 8.2.35, 8.3.36, 8.4.27, 8.5.12, or later. Patched PHP 7.x versions are still to be determined.
- Set session.upload_progress.enabled=0 and memory_limit=-1 in your php.ini file. Note that these are only partial mitigations, it’s still recommended to update the PHP version instead.
- Restrict outbound access from the server to prevent reverse shells or external payload fetching, but those shouldn’t be a replacement for patching PHP.
- If patching is not immediately possible, check whether your WAF/CDN provider has released a mitigation; Cloudflare, Fastly, Google, Vercel, Akamai, Imperva and others have published guidance.
Reported to the PHP security team on August 24, 2026; patched and publicly disclosed on October 21, 2026.
- https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp
- https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w
- https://calif.io/php2shell/#php-5-4-0-rce
- https://securitylabs.datadoghq.com/articles/php2shell-critical-vulnerabilities-in-php/
- https://www.crowdstrike.com/en-us/blog/crowdstrike-protects-customers-from-php-rce-zero-days/
- https://www.wiz.io/blog/php2shell-php-rce