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.

Critical Takeaway: Immediate Patching Required

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).

9.2
CVSS v4.0 severity score (Unauthenticated Remote Code Execution)
PHP 5-8.5
Affected interpreter versions across legacy & current branches
0
Authentication required; triggers via raw inbound HTTP requests
RCE
Arbitrary native shell execution under web user privileges
Section 1
Under the Hood: Zend Engine & longjmp()
01

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:

CVE-2026-109618
OOM Abort & Uninitialized Memory Poisoning

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.

CVE-2026-109619
Stale Global State & Cross-Request Dangling Pointers

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.

Normal PHP Request Lifecycle vs. php2shell Execution Hijack
Safe / Patched Lifecycle
1. Inbound HTTP Request Received
↓
2. Clean Struct Allocation & Zeroing
↓
3. Zend Bytecode Execution
↓
4. OOM Guard Checks & Graceful Teardown
↓
Worker State Completely Sanitized for Next Request
All global pointers reset to NULL; no uninitialized memory dereferencing.
php2shell Exploitation Flow
1. Attacker Transmits Crafted Payload Triggering OOM
↓
2. longjmp() Skips Variable Initialization
↓
3. Cleanup Routine Treats Raw Memory as Valid Pointers
↓
4. Dangling State Persists in Recycled FPM Worker
↓
5. Arbitrary Code Execution (/bin/sh spawned)
Memory corruption executed at the C engine level before user PHP code handles the request.
Section 2
Exploit Delivery & Attack Vectors
02

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
Section 3
Remediation & Defensive Playbook
03

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:

1
Deploy Official PHP Engine Security Patches
Upgrade your PHP interpreters to the patched releases issued on October 21, 2026:
  • 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
For Debian/Ubuntu, RHEL, AlmaLinux, Rocky Linux, or Alpine, ensure your distribution repositories have applied the vendor backport packages and restart php-fpm.
2
Disable session.upload_progress (Immediate Workaround)
If an immediate runtime upgrade requires scheduling a maintenance window, neutralize the primary unauthenticated attack vector by disabling upload progress tracking in your global php.ini:
Hardening Configuration — 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
3
Enforce Aggressive Worker Recycling in PHP-FPM
To prevent the cross-request dangling pointer exploit (CVE-2026-109619) from accumulating on persistent worker processes, configure PHP-FPM to kill and respawn worker processes after a small number of requests:
Process Pool Recycling — php-fpm.d/www.conf
; Recycle workers frequently to clear tainted heap state
pm.max_requests = 100
pm.process_idle_timeout = 10s
4
Restrict Inbound Request Body Limits at Web Server Edge
Configure Nginx or Apache to drop oversized requests before passing them to the FastCGI backend. For example, set client_max_body_size 10M; in Nginx to block gigantic memory-exhaustion payloads.
5
Audit Active Running Interpreters
Verify the active version running in production memory (do not just check the CLI binary, as the FPM daemon may not have reloaded):
Terminal — Linux Shell
# 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
Section 4
Frequently Asked Questions
04

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
🛡️
Taylor Blake, CISSP
Lead Cybersecurity Architect & Creator of isipPublic

I work in enterprise network security with extensive background in threat intelligence, vulnerability analysis, perimeter segmentation, and zero trust architecture. I write about actionable, production-proven security practices. Read more at isippublic.com/about.