Recently, the PHP web security community has been highly concerned about two serious vulnerabilities collectively named PHP2Shell: CVE‑2026‑109618 and CVE‑2026‑109619.

Both vulnerabilities are located in the PHP engine core, in request handling and memory‑management mechanisms. Both have a CVSS v4.0 score of 9.2 out of 10, classified as critical. An attacker can potentially trigger memory corruption with carefully crafted HTTP requests without authentication, ultimately achieving remote code execution (RCE) on the server.
PHP is widely used by content management systems such as WordPress, Drupal, Joomla, and MediaWiki, so the potential impact is extensive. After disclosure, security vendors issued alerts and observed attempts to exploit the vulnerabilities. Organizations including Palo Alto Networks, Red Hat, and JFrog published technical analyses and remediation guidance.
What makes this incident particularly notable is that the vulnerabilities do not stem from a PHP plugin or web application, but from defects in the PHP engine’s handling of abnormal exits, memory release, and request‑state cleanup. They expose a long‑standing runtime security question: when a request terminates abnormally, how can we ensure its internal state does not contaminate subsequent requests?
1. Root cause: memory‑state management flaws in the PHP request lifecycle
When PHP handles an HTTP request it creates many temporary data structures, including strings, arrays, session data, uploaded file metadata, and internal objects. These are typically allocated in request‑specific memory regions and cleaned up when the request finishes.
To handle severe errors, PHP historically used mechanisms such as zend_bailout(), which employ longjmp() to jump out of the current execution context and abort ongoing operations.
While this allows a rapid abort of a failing request, it introduces a risk: the program may jump out before data structures are fully initialized or cleanup is complete.
If the exceptional control path does not synchronously update relevant pointers and state flags, subsequent cleanup code may access invalid data or allow freed memory to be reused by other code.
The two PHP2Shell vulnerabilities expose this issue from different angles.
1. CVE‑2026‑109618: OOM‑related memory corruption leading to RCE
This vulnerability corresponds to the PHP security advisory GHSA‑w8hw‑w9fx‑j79w.
Its root cause is an inconsistency between PHP’s exceptional exit mechanism and the initialization/cleanup flow for request memory when handling out‑of‑memory (OOM) conditions.
Mechanism in brief:
Step 1: PHP begins processing a request and creates internal data structures.
When the server receives an HTTP request, especially a multipart/form-data file upload, PHP parses the request content before application code executes and creates HashTable objects, strings, upload metadata, and session‑related structures. These structures may require multiple dynamic allocations to complete initialization.
Step 2: An attacker triggers memory allocation failure via request content.
An attacker can craft special requests that cause PHP to consume large amounts of memory while parsing. When allocations reach memory_limit or other thresholds, PHP triggers an OOM error.
The critical issue is that some request data structures may already be referenced by other internal modules but have not finished initialization.
Step 3: longjmp() causes initialization or cleanup to be skipped.
PHP may call zend_bailout() which uses longjmp() to jump out of the current execution context. This can bypass initialization, rollback, or pointer‑cleanup code that would otherwise run.
At this point, PHP may still hold pointers to partially initialized structures that are not safe to use.
Step 4: The request cleanup path accesses invalid state.
After a failed request start or when an exception occurs, PHP still proceeds to request shutdown and resource cleanup. If the cleanup code treats partially initialized structures as valid, uninitialized memory reads, invalid pointer dereferences, and memory corruption can result.
Under certain deployment and heap‑layout conditions, an attacker can further manipulate heap allocation patterns so these erroneous accesses turn into exploitable memory corruption, ultimately achieving remote code execution.
Notably, this attack can occur before application‑level PHP code runs, so updating only CMS or plugin code is insufficient.
2. CVE‑2026‑109619: stale global state and cross‑request Use‑After‑Free
This vulnerability corresponds to the PHP security advisory GHSA‑6wmf‑4rv5‑p3rp.
Unlike the first vulnerability, which involves partially initialized structures during OOM handling, the second centers on the fact that after freeing a request’s memory, PHP did not ensure that longer‑lived global state no longer referenced that memory.
This creates a classical Use‑After‑Free (UAF) condition.
To understand this, consider how PHP workers operate.
In common deployments such as Apache mod_php or PHP‑FPM, the server does not typically restart a PHP process for every HTTP request. Instead, a long‑running worker handles many requests sequentially.
For example:
- Worker 1 handles request from user A.
- When that request finishes, PHP frees the temporary memory used for the request.
- The same worker then handles a request from user B.
Under normal conditions, the previous request’s temporary state should be fully cleaned so the new request starts from a clean slate.
The flaw in CVE‑2026‑109619 causes that isolation to break along certain exceptional paths.
Step 1: During request handling, PHP stores temporary memory addresses in longer‑lived state.
PHP has internal variables and state with lifetimes longer than a single request—global pointers, error/backtrace information, and OPcache‑related state among them. When these states reference request memory, their references must be maintained consistent with the request lifecycle.
However, some execution paths can store addresses that belong to the current request in these longer‑lived states.
In other words, an address that should become invalid at request end is stored in a variable that can persist across multiple requests.
Step 2: A fatal error interrupts cleanup before pointers are reset.
If PHP encounters OOM or another fatal error, zend_bailout() may use longjmp() to immediately exit the current execution context. If this jump occurs before pointer‑cleanup runs, PHP may not have the opportunity to set the long‑lived pointers to NULL or otherwise reset them.
Thus, the request memory may be freed but global state still holds the old address—a stale pointer.
Step 3: Freed memory is later reallocated for other purposes.
When the request ends, PHP frees its memory region. Freeing memory does not guarantee that the memory contents are zeroed or that all pointers to that address become invalid.
Consequently, long‑lived pointers can continue to reference freed memory, creating Use‑After‑Free conditions.
Step 4: The same worker processes a new request and may access stale pointers.
When the worker processes the next HTTP request, it reinitializes parts of the request state. If certain global state variables were not fully reset, the new request may access stale pointers before those states are properly initialized.
Moreover, new allocations for the new request may reuse the previously freed memory addresses. A pointer that originally referred to data from the prior request could now point to new data in the new request’s context.
If an attacker can influence the new allocation contents, they may be able to control data that is used by internal PHP code that the stale pointer references.
Step 5: memory reuse and state confusion can be chained to code execution.
Research has shown that PHP’s session upload‑progress handling is an important attack surface. While processing multipart/form-data uploads, PHP may record upload progress and write related information into session files. When a later request reads that session, PHP parses serialized data.
If internal pointers left by an abnormal exit are still visible, and the new request reuses the corresponding memory, attacker‑controlled data can flow into internal processing paths that should not trust such data.
In specific exploit chains, this state confusion can affect object deserialization, serialization write‑back, and other operations, enabling control of program flow and arbitrary code execution.
JFrog’s technical analysis notes that exploit chains involve session data deserialization, internal zval lifecycle structures, and pointers not cleaned after abnormal exits. Researchers also analyzed error backtrace state in PHP 8.5 and OPcache shared‑memory state as other long‑lived paths.
Thus, CVE‑2026‑109619 is more than a simple “data leak from one request to the next.” Its danger lies in request memory being freed while cross‑request internal state still references that memory; when the memory is reused by subsequent requests, an attacker can influence the PHP engine’s own execution.
3. Relationship between the two vulnerabilities
The two issues share similar underlying causes but are distinct vulnerabilities.
| Comparison | CVE‑2026‑109618 | CVE‑2026‑109619 |
| Core problem | Request state left partially uninitialized due to OOM | Stale pointers retained in long‑lived state after abnormal exit |
| Primary memory issue | Partially initialized structures used incorrectly | Freed memory accessed by subsequent code |
| Key mechanism | longjmp() interrupting init and cleanup | Cross‑request pointers and state not reset |
| Main risk | Memory corruption, uninitialized memory access | Use‑After‑Free, state confusion |
| Attack characteristics | Can trigger during request startup | Some exploit paths require the same worker to handle consecutive requests |
Both reveal deep defects in PHP’s exceptional handling and request lifecycle management. While they may be linked in some exploit chains, RCE can be achieved in some environments without chaining both flaws.
2. Why are these vulnerabilities especially dangerous?
The danger derives from three main factors.
First, the flaws are in the PHP engine core.
Attackers do not need to find a specific plugin or CMS bug. Any PHP request handling path that meets the conditions may be affected.
Second, exploits may not require authentication.
An attacker can craft network requests that trigger PHP’s exceptional paths, and in some deployments the attack may occur before application‑level PHP code runs.
Third, long‑running workers amplify cross‑request state issues.
In typical web architectures, a worker processes many requests in sequence. If stale state from a previous request is not cleared, subsequent requests are at risk.
This shows that runtime memory safety depends not only on correct single‑request handling but also on reliable isolation between requests.
3. How did PHP fix this?
PHP released security updates on October 21, 2026, fixing the following versions:
- PHP 8.5.12
- PHP 8.4.27
- PHP 8.3.36
- PHP 8.2.35
The fixes address exceptional exits and request‑state management from multiple angles, not just a single out‑of‑bounds access.
1. Change OOM handling.
For CVE‑2026‑109618, PHP adjusted soft‑OOM handling to avoid using longjmp() to abort key operations in the middle. The new approach defers soft‑OOM handling to later VM safe points so current operations can complete necessary cleanup. If memory usage reaches a higher hard threshold, PHP will call _exit() to terminate the process and avoid running in an inconsistent memory state.
2. Strengthen long‑lived state cleanup.
For CVE‑2026‑109619, PHP improved state reset during request shutdown to ensure error backtrace information, session state, OPcache and other long‑lived internal state do not retain pointers to freed request memory.
3. Restrict object behavior during upload‑progress parsing.
PHP also changed how objects are handled when parsing session upload‑progress data to avoid triggering autoloading and destructor calls that could open object‑injection paths in that parsing path.
These changes follow an important principle: abnormal exits must not only stop current execution but must also ensure any state that spans the operation’s lifecycle is correctly reset.
4. Actions for site administrators
1. Check PHP runtime version.
On servers run:
php -v
You can also temporarily create a phpinfo.php to inspect the PHP version used by the web environment. Note that CLI PHP and the PHP‑FPM instance serving the web may be different versions.
2. Upgrade to patched versions as soon as possible.
Recommended upgrades:
- PHP 8.5.12 or later;
- PHP 8.4.27 or later;
- PHP 8.3.36 or later;
- PHP 8.2.35 or later.
If you use cloud or shared hosting, contact your provider to confirm the PHP runtime has been updated. If you manage servers yourself, install patched packages from your OS package manager or PHP official sources and restart PHP‑FPM, Apache, or relevant workers.
3. Special handling for older versions.
PHP 8.1 and earlier are out of regular official support and should not be assumed to receive the same updates as 8.2+ branches. The PHP project has provided some patch sources for older branches, and some Linux distributions or commercial maintainers may offer backported fixes. Administrators must verify that installed packages include the security fixes rather than relying solely on version numbers. Environments without available fixes should prioritize migration to supported versions.
4. Temporary mitigations do not replace upgrading.
If immediate updates are not possible, follow vendor guidance for temporary mitigations, for example:
- Disable
session.upload_progress.enabledto reduce exposure of the upload‑progress parsing path; - Adjust fatal error/backtrace behavior according to version and environment;
- Tighten memory limits and request‑size settings to lower the chance of triggering exceptional paths;
- Restrict access to publicly exposed PHP management interfaces and services;
- Use WAFs such as Cloudflare or ModSecurity to filter abnormal requests.
These measures reduce some risk but cannot fully eliminate the vulnerability. Some mitigations may affect normal uploads, error diagnosis, or server resource protections.
5. After upgrading, check for signs of compromise.
Exploit attempts may have occurred before or after disclosure, so upgrading does not negate the need to investigate prior activity.
Recommended checks:
- Look for anomalous requests in web server and PHP‑FPM logs;
- Detect worker processes spawning shells, downloaders, or unexpected subprocesses;
- Scan website directories for unknown PHP files, webshells, or backdoors;
- Check for suspicious cron jobs, system services, or accounts;
- Monitor abnormal outbound connections, CPU usage spikes, or unusual network traffic.
If evidence of remote code execution is found, follow incident response procedures: isolate the host, preserve evidence, audit credentials, and only restore services after confirming the threat is removed.
5. Conclusion: the real issue is how abnormal state crosses the request lifecycle
The PHP2Shell vulnerabilities underscore that software security depends not only on correctness in normal execution paths but also on maintaining consistent state under exceptional conditions.
CVE‑2026‑109618 exposes partially initialized state caused by OOM‑driven abnormal exits; CVE‑2026‑109619 exposes stale pointers that survive request termination and can affect subsequent requests.
From a broader engineering perspective, these bugs highlight three principles:
- Resource lifecycles must be consistent. After memory is freed, all references must be invalidated or safely reset.
- Abnormal exits must preserve state integrity. Terminating execution is not enough; internal state and resource relationships must also be handled.
- Requests must be reliably isolated. Long‑running workers must not allow a prior request’s abnormal state to contaminate later requests.
The impact extends beyond PHP: any long‑running server that reuses memory and processes repeated tasks must carefully address cross‑task state contamination, abnormal exits, and Use‑After‑Free risks.
For PHP site administrators, the most important action is to confirm your environment has the security patches and to upgrade promptly.
References
- Technical analysis of PHP2Shell vulnerabilities: JFrog Security Research, October 21, 2026.
- Palo Alto Networks Unit 42: PHP2Shell threat briefing, updated October 29, 2026.
- Red Hat: RHSB‑2026‑013, PHP request‑handling memory corruption advisory.
- Elastic Security Labs: PHP2Shell detection and attack behavior analysis.
- PHP official advisories: GHSA‑w8hw‑w9fx‑j79w (CVE‑2026‑109618) and GHSA‑6wmf‑4rv5‑p3rp (CVE‑2026‑109619).
Note: exploitability depends on PHP version, deployment, configuration, and request handling paths. This article describes mechanisms disclosed by public research and does not imply identical exploitability across all PHP deployments.
▶️ Enjoyed this article? Content creation takes effort!
Follow our YouTube channel:
AI Rosetta
Your likes, subscriptions and shares are our greatest support! 🙏
More AI news at: https://www.airosetta.com