PHP2Shell explained: how two PHP memory bugs can lead to unauthenticated RCE
 Conceptual illustration; it explains the memory paths and is not exploit code or a real compromise. PHP’s 21 October security release fixes two separate flaws in the runtime itself, tracked as CVE-2026-109618 and CVE-2026-109619. Both are rated 9.2 (Critical) under CVSS 4.0 and can allow remote code execution without credentials or user interaction. That describes the potential impact, not equal exploitability on every hosting stack. The PHP team’s [security advisory](https://www.php.net/archive/2026.php#2026-10-21-5) and the [upstream report for CVE-2026-109618](https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w) explain the memory paths. **CVE-2026-109618: out-of-memory corruption.** PHP’s multipart/form-data parser handles upload requests. Some request shapes can make PHP run out of memory even when they appear to respect ordinary limits—for example, many part headers whose in-memory representation is much larger than their wire size, or nested/empty upload fields that still create parser metadata. When allocation fails, PHP uses an early-exit path. In affected code, request state can be left only partly initialized; shutdown cleanup later treats that state as valid and reads it. The PHP team demonstrated the clearest application-independent route on Apache’s mod_php, where cleanup runs even after request startup fails. The upstream advisory says PHP-FPM can still be susceptible after normal startup, although it documents no complete FPM exploit; the exact exposure depends on SAPI, build and configuration. **CVE-2026-109619: stale global state / use-after-free.** Long-lived PHP workers retain some global error, session, object or extension state between requests. A first request can terminate on a fatal error, timeout or memory exhaustion before that state is reset. PHP frees the request’s memory, but a worker-level reference can remain—or be repopulated during shutdown. If that same worker then processes another request, an operation that runs before normal initialization may consume the stale state. The maintainers describe the necessary producer/consumer pattern and a carefully arranged heap; confirmed consumers include early INI diagnostics and session-related paths. This is a multi-request memory-lifetime problem, distinct from simply sending one oversized upload. See the [CVE-2026-109619 advisory](https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp). That SAPI distinction is why “critical” does not mean every PHP site is equally easy to compromise. PHP says all web-serving installations should update and identifies mod_php as the highest-risk configuration. Red Hat’s assessment says its usual PHP-FPM deployment makes one early-startup path difficult to exploit, while still treating affected packages as needing fixes. NHS England says researchers demonstrated RCE proof-of-concepts for both flaws in products integrating PHP, including WordPress, Drupal and Joomla; that is evidence of working demonstrations, not proof that every installation—or those vendors’ own services—was compromised. AWS reported attempts against its honeypots beginning Oct. 17 and after disclosure, but says it cannot establish whether those attempts would have succeeded on real systems. Review from that earliest reported date; an attempt is not a confirmed victim. ([Red Hat’s assessment](https://access.redhat.com/security/vulnerabilities/RHSB-2026-013), [NHS alert](https://digital.nhs.uk/cyber-alerts/2026/cc-4875), [AWS telemetry report](https://aws.amazon.com/blogs/security/amazon-threat-intelligence-identifies-php2shell-exploitation-prior-to-public-disclosure-in-madpot/)) **What to do.** The complete fix is a patched PHP runtime: 8.5.12, 8.4.27, 8.3.36 or 8.2.35, or a vendor package with a verified backport. Inventory PHP across hosts, FPM pools, Apache modules, CGI/other SAPIs, containers and managed runtimes; rebuild images and restart workers after updating. PHP 8.1 and older are upstream end-of-life, so verify a vendor backport or migrate to a supported branch. Updating WordPress or a plugin alone does not repair PHP. If an emergency upgrade is delayed, PHP’s temporary controls only reduce specific paths: disable session.upload_progress.enabled=0 before requests reach PHP and restart workers; on PHP 8.5, also set fatal_error_backtraces=0. For CVE-2026-109618, the advisory includes administratively enforcing memory_limit=-1, keeping post_max_size conservative and bounding multipart input at the proxy/server. Because removing PHP’s per-request memory limit changes availability risk, use independent container/cgroup limits and follow the vendor guidance; PHP explicitly says these measures are not a complete fix. Do not use RLIMIT_AS or RLIMIT_DATA as substitutes. **New note, 23 October:** PHP disclosed a separate, unlikely RCE vector tracked as CVE-2026-115560. It requires session upload progress to remain enabled and an unusual configuration: set session.serialize_handler to php_binary or php_serialize, then switch it to php at runtime before session_start. The project advises keeping upload progress disabled until the next regular bugfix release; the full advisory is due with that release. This is not a renumbering of the two PHP2Shell CVEs. Our earlier [PHP disclosure thread](https://www.mushimu.com/post/9110) tracks the incident timeline; this post focuses on the technical failure modes and defensive response. ~Cybersecurity ~PHP ~CVE