On October 21, 2026, the PHP development group published an emergency security release across all active maintenance branches (PHP announcement 2026-10-21-5) to remediate two catastrophic Remote Code Execution (RCE) vulnerabilities: CVE-2026-109618 and CVE-2026-109619, collectively dubbed php2shell.
Unlike standard web application flaws that depend on vulnerable application code (such as SQL injection in an eCommerce plugin or unsafe deserialization in a CMS theme), php2shell resides directly within the low-level C Zend Engine of PHP itself. Any unauthenticated attacker can send crafted HTTP payloads to trigger memory corruption and achieve arbitrary shell execution on the host server under the permissions of the web user.
Because the vulnerability impacts how PHP handles out-of-memory (OOM) fatal errors and worker process lifecycles, millions of production deployments running WordPress, Laravel, Drupal, Magento, Symfony, and custom web applications are exposed if their underlying PHP runtime has not been patched.
Both CVE-2026-109618 and CVE-2026-109619 carry a CVSS v4.0 score of 9.2 (Critical). Exploitation does not require authentication or application-level bugs. Administrators must immediately update PHP runtimes to versions 8.5.12, 8.4.27, 8.3.36, or 8.2.35 (or vendor-backported equivalents).
To understand how php2shell turns an out-of-memory error into full remote code execution, you have to look at how the C language handles control-flow jumps. Unlike C++ or Rust, pure C does not have native structured exception handling (stack unwinding with destructor execution). To simulate non-local jumps when a critical error occurs, PHP uses POSIX setjmp() and longjmp() primitives.
When an unrecoverable out-of-memory (OOM) error occurs in the Zend memory manager (ZendMM), PHP cannot allow standard linear execution to continue. It executes a longjmp() directly to the top-level request bailout handler. That sudden jump breaks the contract of structured memory management in two specific, lethal ways:
PHP initiates memory allocation for request buffers (such as multipart form data or session tracking). When an OOM occurs midway, longjmp() abruptly halts execution before pointers and internal struct fields are initialized. The subsequent request cleanup and garbage collector routines erroneously assume that these memory addresses contain valid zval pointers and hash tables. By shaping the memory heap beforehand, an attacker coerces the cleanup routine into dereferencing attacker-crafted pointers, enabling arbitrary memory write and control-flow hijacking.
In modern web servers (PHP-FPM, mod_php, FrankenPHP, LiteSpeed), worker processes persist across thousands of requests to avoid process startup overhead. When a fatal bailout occurs via longjmp(), internal global pointers (such as request context structs and Zend execution state) are left pointing to memory segments that have already been freed. When the next legitimate or malicious HTTP request is handled by the same worker, PHP accesses this dangling pointer state prior to fresh reinitialization, causing heap corruption and remote shellcode execution.
Attack telemetry reported by threat intelligence teams (including watchTowr, Sansec, and Cloudflare) reveals how adversaries weaponize these memory management flaws without requiring any application-level credentials:
1. Exploitation via session.upload_progress
PHP includes a built-in feature enabled by default on many distributions: session.upload_progress.enabled. When an RFC 1867 multipart form upload includes a parameter matching session.upload_progress.name, PHP automatically initializes session tracking even if the target web script never touches $_SESSION. By sending nested multipart form boundaries or calculating precise payload sizes, attackers reliably trigger ZendMM out-of-memory errors at the exact instruction boundary needed to corrupt worker heap memory.
2. Worker Poisoning in Persistent Environments
In high-performance configurations (such as Nginx + PHP-FPM or Apache Event MPM with FastCGI), worker processes stay alive indefinitely to handle thousands of requests. An attacker can execute a two-stage attack:
- Stage 1 (Poison): Send request A to trigger CVE-2026-109619, leaving dangling global pointers on worker process PID 4012.
- Stage 2 (Trigger): Send request B to worker PID 4012 containing a tailored binary payload in headers or body that matches the memory address expected by the dangling pointer, triggering immediate shell execution.
| Vulnerability Vector | CVE-2026-109618 | CVE-2026-109619 | Application-Level Flaw (e.g. eval) |
|---|---|---|---|
| Root Cause | longjmp() uninitialized request cleanup | longjmp() dangling pointers across requests | Unsafe user input validation |
| Vulnerable Layer | Core C Zend Engine | Core C Zend Engine | PHP Application Script |
| Authentication | None (Unauthenticated) | None (Unauthenticated) | Depends on application route |
| Bypasses CMS Firewalls? | Yes (Executes before CMS loads) | Yes (Executes before CMS loads) | Often blocked by CMS plugins |
| Impact | Direct Remote Code Execution (RCE) | Direct Remote Code Execution (RCE) | RCE, SQLi, or Data Leak |
For systems and servers that do run PHP, immediate remediation is required. Because active exploitation in the wild has already been confirmed, security teams must follow this prioritized defense playbook:
- PHP 8.5: Update to 8.5.12 or higher
- PHP 8.4: Update to 8.4.27 or higher
- PHP 8.3: Update to 8.3.36 or higher
- PHP 8.2: Update to 8.2.35 or higher
php-fpm.
php.ini:
; Neutralize the RFC 1867 upload progress trigger
session.upload_progress.enabled = Off
; Disable unneeded dynamic wrappers if possible
allow_url_include = Off
expose_php = Off
; Recycle workers frequently to clear tainted heap state
pm.max_requests = 100
pm.process_idle_timeout = 10s
client_max_body_size 10M; in Nginx to block gigantic memory-exhaustion payloads.
# 1. Check CLI binary version
php -v
# 2. Restart PHP-FPM to load new shared libraries into running workers
sudo systemctl restart php8.3-fpm # (replace with your active version)
# 3. Check listening sockets and running worker binaries
ps aux | grep php-fpm
Yes. If the underlying server is running an unpatched version of the PHP interpreter, any application running on that server is vulnerable. The vulnerability exists within the C-based Zend Engine, not in application PHP code. An attacker triggers the flaw during HTTP request parsing before CMS security plugins or application firewalls are even invoked.
A WAF provides vital defense-in-depth, but it is not a complete replacement for patching. Attackers continuously refine their payload encodings and multipart boundary structures to bypass signature-based WAF rules. Only updating the PHP binary to a patched release fixes the underlying C longjmp() pointer mismanagement.
CVE-2026-109618 occurs when an out-of-memory error halts initialization, leaving request structs uninitialized so that Zend cleanup routines dereference invalid memory. CVE-2026-109619 occurs when error unwinding leaves dangling pointers in global state that persist across persistent worker requests (like PHP-FPM), allowing an attacker to trigger memory corruption on a subsequent request.
No. The vulnerability exists entirely within the core Zend Engine memory manager. While default runtime features such as session.upload_progress make unauthenticated triggering straightforward via RFC 1867 multipart form uploads, the underlying flaw is rooted in core C-level longjmp() handling and does not depend on third-party PECL or C extensions.
If you are running unsupported versions (like PHP 7.4, 8.0, or 8.1), official updates are not provided by php.net. You must either upgrade to a supported PHP branch (8.2+), utilize enterprise LTS vendor support (such as Ubuntu Pro, Red Hat Enterprise Linux, or AlmaLinux ELevate), or deploy strict network isolation and disable session.upload_progress.enabled.
Strengthen Your Enterprise Defense Architecture
Modern application security requires defense-in-depth: from runtime memory protection to Zero Trust access control and post-quantum encryption.
Read Zero Trust Architecture Guide