Back to Production Traps
Cyber Security9 min read24 Oct 2026

PHP2Shell (CVE-2026-109618) Explained: Architecture & Patch Guide

How the two-request PHP2Shell RCE exploit (CVE-2026-109618 & CVE-2026-109619) hijacks web workers pre-login, and how to patch and lock down your servers.

Author: Logic42 Sovereign Engineering Practice

PHP2Shell (CVE-2026-109618 and CVE-2026-109619) is a pair of critical, unauthenticated Remote Code Execution (RCE) vulnerabilities (CVSS 9.2) in the core PHP runtime uncovered during AI-assisted code audits. The flaws let an attacker trigger an out-of-memory abort on Request #1 and hijack leftover memory pointers on Request #2 to execute shell commands before application login code runs.

Because PHP powers roughly 75% of websites with a known server-side language—spanning content platforms, e-commerce checkouts, and internal banking portals—the disclosure triggered immediate worldwide advisories from CISA, Rapid7, and Palo Alto Networks. The vulnerabilities surfaced when frontier AI reasoning models (including Anthropic's Claude Mythos working alongside Alpha-Omega and the PHP Foundation) audited decade-old C memory-handling routines inside the core PHP engine.

Most security advisories bury the remediation under dense C pointer arithmetic. Below, we break down how the two-request exploit works in practice, how to verify and patch active servers in five minutes, and how to lock down legacy PHP fleets that can't be upgraded overnight.


Why Passwords and Login Screens Don't Stop PHP2Shell

When a critical web vulnerability breaks, the first question most teams ask is: "We enforce strong passwords, Two-Factor Authentication (2FA), and application firewalls. Aren't we protected?"

Not against this flaw. PHP2Shell triggers inside the underlying PHP engine at the front door, before your application router, login screen, or security middleware even initializes.

To visualize how the exploit bypasses authentication, think of a PHP web worker (PHP-FPM or mod_php) as an Express Bank Teller Booth:

How PHP2Shell Works: The Two-Request Worker Memory Heist

  1. The Normal Rule (Wipe the Desk Between Visitors): Spawning a brand-new process for every web visitor is too slow. Instead, your web server keeps the same Worker Process sitting at a desk serving Visitor #1, Visitor #2, and Visitor #3 back-to-back. After each request finishes, the worker shreds the temporary request data and wipes its memory workspace clean before taking the next connection.
  2. Request #1 (CVE-2026-109618: The Memory Overload Abort): The attacker arrives as Visitor #1 and submits a malformed payload designed to trip the server's Out-of-Memory (OOM) limit during request setup. An emergency abort (longjmp()) fires immediately. Because the worker jumps straight out of its normal execution path, it skips a portion of the desk-wiping sequence, leaving an uninitialized "Override Slip" (a dangling memory structure) sitting on the counter.
  3. Request #2 (CVE-2026-109619: Hijacking the Uncleaned Worker): Milliseconds later, the attacker sends Visitor #2 to that exact same worker booth. Before the application even asks for a session cookie or password, the worker reads the leftover Override Slip from Visitor #1 (Use-After-Free) and executes the attacker's command (ROOT SHELL).
  4. The Remediation (Patch the Engine, Flush RAM Workers & Lock the OS): You upgrade PHP to the patched release (so the worker always sanitizes memory during an abort), restart the worker pool (so workers still sitting at dirty desks in RAM are replaced), and apply a kernel syscall lock (systemd / eBPF) so a web worker can't ever spawn a command shell.

Quick Verification Checklist for Engineering & Hosting Teams

If an external vendor, cloud team, or managed hosting provider operates your PHP servers, send them these three verification questions today:

Urgent verification check for PHP2Shell (CVE-2026-109618 & CVE-2026-109619):
1. Are all PHP runtimes and containers upgraded to 8.5.12+, 8.4.27+, 8.3.36+, or 8.2.35+?
2. Have php-fpm and apache2/httpd worker pools been restarted so no pre-patch binaries remain in RAM?
3. For any legacy PHP 8.1 or older workloads, have we disabled session.upload_progress.enabled and restricted shell execution?

The 5-Minute Verification & Patch Guide

If you have terminal access to your infrastructure, follow this five-step triage sequence to audit and patch your nodes:

PHP2Shell 5-Minute Decision & Patch Flowchart

PHP Release BranchVulnerable VersionsPatched Safe VersionOfficial Upstream StatusAction Required Today
PHP 8.58.5.0 to 8.5.118.5.12 or laterActive SupportUpgrade binary + restart php-fpm / apache2
PHP 8.48.4.0 to 8.4.268.4.27 or laterActive SupportUpgrade binary + restart php-fpm / apache2
PHP 8.38.3.0 to 8.3.358.3.36 or laterSecurity SupportUpgrade binary + restart php-fpm / apache2
PHP 8.28.2.0 to 8.2.348.2.35 or laterSecurity SupportUpgrade binary + restart php-fpm / apache2
PHP <= 8.1 (7.4, 8.0, 8.1)All versions (5.4 to 8.1)No official binary patchEnd-of-Life (EOL)Apply WAF + systemd Kernel Containment immediately

Step 1: Audit Running PHP Versions Across Host and Containers

Check both the CLI binary and the active php-fpm daemon, as multi-version hosts frequently bind web pools to an older minor release:

# Check CLI and FPM versions on the host OS
php -v
php-fpm -v || /usr/sbin/php-fpm8.3 -v

# Audit all running Docker containers with PHP installed:
docker ps --format "{{.Names}}" | xargs -I {} sh -c 'echo "=== {} ==="; docker exec {} php -v 2>/dev/null'

Step 2: Upgrade to the Patched Runtime Binary

# Ubuntu / Debian (including Ondrej PPA):
sudo apt-get update && sudo apt-get install --only-upgrade -y 'php*'

# RHEL / AlmaLinux / Rocky Linux / Amazon Linux:
sudo dnf upgrade -y 'php*'

Step 3: Flush Vulnerable Worker Pools From RAM

Upgrading packages via apt or dnf replaces the binary on disk, but it doesn't replace php-fpm or apache2 worker processes that are already resident in memory. Until you restart the daemon, your server remains exploitable:

# Restart PHP-FPM (adjust version for 8.2, 8.3, 8.4, or 8.5)
sudo systemctl restart php8.3-fpm

# Restart Apache mod_php or reload Nginx upstream sockets:
sudo systemctl restart apache2 || sudo systemctl restart httpd
sudo systemctl reload nginx

# Confirm the master process start time reflects the restart:
ps -eo pid,lstart,cmd | grep -E "php-fpm|apache2|httpd" | grep -v grep

SAPI Memory Forensics & Zero-Trust Containment for Legacy Fleets

In enterprise environments, the biggest operational risk is End-of-Life (EOL) version drift. Across financial services, telecommunications, and public-sector estates, internal billing portals and vendor appliances frequently remain pinned to PHP 7.4, 8.0, or 8.1 because upgrading to PHP 8.3 breaks legacy dependencies.

When upstream binary patches aren't available for an EOL branch, you must break the exploit chain at the reverse proxy, the PHP SAPI configuration, and the Linux kernel syscall boundary.

PHP2Shell Memory UAF vs Logic42 4-Layer Zero-Trust Containment Architecture

How CVE-2026-109618 and CVE-2026-109619 Chain Inside zend_mm_heap

  1. CVE-2026-109618 (Uninitialized Heap State via OOM longjmp()): When a PHP worker exceeds memory_limit during early request parsing, the Zend Engine invokes _zend_bailout(), executing a C longjmp() back to the SAPI loop. In unpatched builds, specific allocation paths fail to zero-initialize internal structures before the allocation call that triggers the OOM jump. The subsequent cleanup handler reads uninitialized heap bytes that an attacker can groom across prior requests.
  2. CVE-2026-109619 (Global State Use-After-Free in ext/session/session.c): Persistent SAPI workers (PHP-FPM, mod_php, FrankenPHP, LiteSpeed) maintain module globals across requests. During abnormal resets (specifically involving PHP_SESSION_UPLOAD_PROGRESS state tracking in ext/session/session.c), global pointers referencing request-allocated memory (emalloc) are freed during shutdown without being nulled or properly re-initialized on the next cycle. When Request #2 lands on that same worker PID, it dereferences the freed pointer, allowing crafted zend_function structures to divert control flow straight into zend_call_function("system") before index.php loads.

Three Hardening Controls for Legacy and High-Assurance Servers

Whether you're shielding legacy PHP 7.4 / 8.0 / 8.1 workloads during a migration window or enforcing defense-in-depth on patched 8.2 to 8.5 clusters, apply these three controls immediately:

; 1. /etc/php/8.x/fpm/php.ini - Disable upload progress global state & shell execution
session.upload_progress.enabled = 0
expose_php = Off
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,pcntl_exec,dl

; 2. /etc/php/8.x/fpm/pool.d/www.conf - Recycle workers frequently to flush heap state
pm.max_requests = 50

Next, strip PHP_SESSION_UPLOAD_PROGRESS requests at your NGINX reverse proxy before they reach the FastCGI socket, and enforce a Linux systemd seccomp syscall filter so the kernel physically blocks php-fpm from executing /bin/sh, bash, curl, or wget:

# 3. Create a systemd kernel sandbox override for php-fpm:
sudo mkdir -p /etc/systemd/system/php8.3-fpm.service.d
cat << 'EOF' | sudo tee /etc/systemd/system/php8.3-fpm.service.d/hardening.conf
[Service]
# Prevent PHP workers from escalating privileges or modifying web root source files
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/www/html/storage /var/lib/php/sessions /var/log

# Block execve/fork of external shells & binaries at the Linux kernel seccomp layer
SystemCallArchitectures=native
SystemCallFilter=~@process @mount @module @raw-io @reboot @swap
EOF

sudo systemctl daemon-reload && sudo systemctl restart php8.3-fpm

Three-Step Post-Exploitation Forensic Audit

  1. Inspect Live Process Trees for Shell Children Under php-fpm or httpd: Run ps -ef --forest | grep -E "php-fpm|apache2|httpd" -A 5 across every web host. A healthy PHP worker shouldn't ever spawn /bin/sh, bash, python, curl, wget, or nc as a child process.
  2. Hunt Error Logs for Intentional Out-of-Memory (CVE-2026-109618) Probing: Run grep -i "Allowed memory size of" /var/log/php* /var/log/nginx/error.log /var/log/apache2/error.log. A sudden burst of 20+ OOM errors within seconds from a single client IP is the primary signature of heap-grooming probes targeting PHP2Shell.
  3. Scan Web Directories for Recently Modified Scripts: Run find /var/www -type f \( -name "*.php" -o -name "*.phtml" \) -mtime -14 -ls to inspect any executable script created or modified in the last 14 days, and benchmark your perimeter controls using our ISO/IEC 27001 & Zero-Trust Readiness Diagnostic or Enterprise AI & Runtime Security Audit.

AI-assisted vulnerability discovery has permanently compressed the window between source-code auditing and global exploitation. Combining immediate runtime patching with kernel-level syscall containment ensures that memory corruption bugs in web runtimes never become remote shells.

Share this note
THE MONDAY PRODUCTION TRAP DISPATCH · WEEKLY 09:00 MYT

Enjoyed this autopsy? Get next Monday's architecture teardown + SVG blueprints in your inbox.

1 email every Monday morning. Zero marketing fluff — just real VRAM math, MCP security traps, and sovereign lakehouse patterns.

Sovereign Practice Diagnostic
4 Pillars · 16 Calibrated Checkpoints

Auditing Runtime & Agentic Containment?

If your engineering teams are deploying autonomous tool loops, MCP servers, or evaluation sandboxes, our cyber practice conducts confidential architectural reviews to expose link-local leakage, SSRF vectors, and credential harvesting paths.

DIRECT PRINCIPAL ARCHITECT PEER REVIEW · NO SALES PITCH

Debugging this pattern in your own stack? Ask a Principal Architect directly or request a free 48-hour architecture sanity check:

Free in Interactive Diagnostic:Boardroom PDF DossierExcel Working Papers (.CSV)Legal & Kernel Playbook (.MD)
Confidential & Zero Third-Party Telemetry · Encrypted Practice Intake