· Goher K · Web Development & DevOps · 14 min read
How to Fix PHP Remote Code Execution: CVE-2026-109618 & 109619 Patch
Patch PHP2Shell RCE vulnerabilities CVE-2026-109618 and CVE-2026-109619 across PHP-FPM, Apache, cPanel, and Docker with verified emergency remediation steps.
On October 21, 2026, the PHP development team released coordinated emergency security updates addressing two critical vulnerabilities tracked as CVE-2026-109618 and CVE-2026-109619, collectively designated by security researchers as “PHP2Shell”. Rated with a maximum CVSS v4.0 base score of 9.2 (Critical), these vulnerabilities expose virtually all web applications running modern PHP to unauthenticated, remote code execution (RCE) without requiring special privileges, valid user sessions, or vulnerable third-party plugins.
Because the flaw resides in the core C-level memory allocation routines of the PHP engine itself—rather than high-level application code like WordPress, Laravel, Drupal, or Magento—every web server dispatching requests through PHP-FPM, Apache mod_php, FrankenPHP, or LiteSpeed is directly exposed. Cybersecurity authorities including the UK National Cyber Security Centre (NCSC), Google Cloud Security, and Cloudflare have issued urgent advisories directing engineering teams to update production runtimes immediately.
This technical guide breaks down the memory architecture underlying PHP2Shell, contrasts the exploitation mechanics of both CVEs, and delivers verified, step-by-step remediation commands across Linux distributions, cPanel/WHM environments, Docker containers, and edge firewalls.

Technical Summary & Threat Overview
To assist Site Reliability Engineers (SREs), DevOps practitioners, and cloud architects in rapid triage, the critical parameters of the PHP2Shell threat are summarized below:
- Vulnerability Identifiers: CVE-2026-109618 & CVE-2026-109619 (PHP2Shell)
- CVSS v4.0 Score: 9.2 Critical (
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H) - Attack Vector: Network / Remote (Unauthenticated HTTP/HTTPS POST requests)
- Exploitation Impact: Arbitrary code execution within web worker privileges (
www-data,nobody, or server account), arbitrary process takeover, and memory corruption - Root Vulnerability Mechanism: Unchecked
longjmp()execution bailouts during memory allocation failures and request-to-global state desynchronization - Affected PHP Branches: PHP 8.2 (≤ 8.2.34), PHP 8.3 (≤ 8.3.35), PHP 8.4 (≤ 8.4.26), and PHP 8.5 (≤ 8.5.11), plus all EOL versions (PHP 5.x, 7.x, 8.0, 8.1)
- Remediation Releases: PHP 8.2.35, PHP 8.3.36, PHP 8.4.27, and PHP 8.5.12
Core Vulnerability Mechanics: The longjmp() Bailout Crisis
To comprehend how PHP2Shell achieves reliable remote code execution, developers must examine how the Zend Engine manages request lifetimes, memory boundaries, and abnormal process terminations.
+-------------------------------------------------------------------------+
| HTTP POST / Multipart Request Stream |
+-------------------------------------------------------------------------+
|
v
+-------------------------------------------------------------------------+
| PHP RFC 1867 Multipart Parser |
| Allocating internal data structures for file upload |
+-------------------------------------------------------------------------+
|
[Payload triggers memory_limit exhaustion mid-allocation]
|
v
+-------------------------------------------------------------------------+
| zend_error(E_ERROR) -> zend_bailout() |
| Abrupt execution jump via longjmp() |
| * Bypasses destructors and cleanups * |
+-------------------------------------------------------------------------+
/ \
/ \
v v
+-------------------------------+ +-------------------------------+
| CVE-2026-109618 | | CVE-2026-109619 |
| Shutdown handlers inspect | | Global engine state retains |
| partially initialized memory | | pointers to freed request |
| as valid data pointers | | memory across worker requests |
+-------------------------------+ +-------------------------------+
\ /
\ /
+-------------------+---------------------+
|
v
+-------------------------------------------------------------------------+
| Heap Manipulation -> Arbitrary Remote Code Execution (RCE) |
+-------------------------------------------------------------------------+The Role of longjmp() in Fatal Error Bailouts
In standard C application development, memory allocated on the heap during a function call must be methodically freed before returning. However, PHP is designed to process web requests with strict execution limits, including execution timeouts (max_execution_time) and memory thresholds (memory_limit).
When a script exceeds these thresholds, PHP cannot afford to gracefully unwind dozens of nested stack frames. Instead, the Zend Engine invokes zend_bailout(), which wraps the C standard library primitive longjmp(). This primitive restores the CPU register state to a previously saved checkpoint (setjmp()), abruptly terminating script execution and jumping directly to the engine’s outer shutdown routines:
/* Conceptual Zend Engine bailout invocation */
ZEND_API void zend_bailout(void)
{
/* Abruptly unwinds stack to top-level request handler */
longjmp(EG(bailout), 1);
}While longjmp() provides a quick abort mechanism, it has an inherent architectural danger: stack variables and heap tracking structures in progress are abandoned immediately. No destructors execute, intermediate pointer registrations are skipped, and partially allocated memory blocks are left orphaned in memory.
CVE-2026-109618: Out-Of-Memory (OOM) Heap Corruption
CVE-2026-109618 specifically targets PHP’s RFC 1867 multipart form-data parsing engine, which handles standard browser file uploads.
When a client transmits an HTTP POST request containing multipart/form-data, PHP reads incoming MIME parts, parses headers, and buffers upload structures into memory. In vulnerable versions, the parser records tracking metadata indicating that a data structure is initialized before the memory allocation for its internal buffer completes.
An attacker constructs a maliciously crafted multipart payload with oversized or deeply nested boundaries designed to exhaust PHP’s memory_limit at the exact byte boundary between structure definition and buffer allocation:
- The allocation attempt exceeds
memory_limit. - The Zend Engine immediately executes
longjmp(), bailing out of the multipart parser. - During request shutdown, PHP runs cleanup handlers that iterate over registered upload structures.
- Because the metadata was marked initialized, cleanup routines attempt to dereference uninitialized or partially initialized pointers.
- By grooming the PHP heap layout through prior HTTP requests, the attacker controls the contents of that uninitialized memory, transforming invalid pointer dereferences into arbitrary code execution.
CVE-2026-109619: Stale Global State Use-After-Free
CVE-2026-109619 affects PHP’s persistent worker architectures, such as PHP-FPM, Apache worker threads, and modern persistent runtimes like FrankenPHP.
Unlike classic CGI where each request spawns a separate OS process that discards its entire address space on exit, worker models reuse worker processes across thousands of successive web requests to achieve high throughput.
During request processing, PHP utilizes global or module-level variables (such as internal stream wrappers, database handles, and error-handling context blocks) that temporarily point to request-allocated memory. Under normal request completion, PHP’s request shutdown cycle (RSHUTDOWN) clears these global pointers.
However, when an abnormal termination is forced via longjmp(), specific error paths fail to reset these temporary global references. As a result:
- Request A is forcefully aborted via a fatal error bailout.
- The memory allocated for Request A is reclaimed by the Zend Memory Manager (
emalloc/efreeheap). - The global state pointer continues to reference that freed address space.
- Request B arrives on the same worker thread. When the engine accesses the global variable, it reads and writes to already-freed memory (a textbook Use-After-Free condition).
- Attackers leverage Request B to overwrite the freed memory with executable shellcode or function pointers, achieving unauthenticated takeover of the worker.
Comprehensive Matrix: Affected vs. Patched Versions
Review the table below to verify the security status of your current PHP runtimes:
| PHP Branch | Status | Vulnerable Releases | Official Patched Release | Upstream Support Status |
|---|---|---|---|---|
| PHP 8.5 | Active Development | 8.5.0 – 8.5.11 | 8.5.12 | Officially Supported |
| PHP 8.4 | General Availability | 8.4.0 – 8.4.26 | 8.4.27 | Officially Supported |
| PHP 8.3 | Active Maintenance | 8.3.0 – 8.3.35 | 8.3.36 | Officially Supported |
| PHP 8.2 | Security Fixes Only | 8.2.0 – 8.2.34 | 8.2.35 | Officially Supported |
| PHP 8.1 | End of Life (EOL) | 8.1.0 – 8.1.31 | No upstream patch | Requires Extended Support / WAF |
| PHP 8.0 | End of Life (EOL) | 8.0.0 – 8.0.30 | No upstream patch | Requires Extended Support / WAF |
| PHP 7.4 | End of Life (EOL) | 7.4.0 – 7.4.33 | No upstream patch | Requires Extended Support / WAF |
Critical Caveat for Legacy Stacks: If your infrastructure runs PHP 7.4, 8.0, or 8.1, the PHP Foundation will not publish official upstream packages. You must either upgrade your application codebase to PHP 8.2+, subscribe to enterprise backport distributions (e.g., TuxCare, Red Hat Enterprise Linux Extended Lifecycle Support, or Ubuntu ESM), or apply rigorous edge firewall filters.
Step-by-Step Server Remediation & Patching
Remediating PHP2Shell requires updating the underlying interpreter package and ensuring that all memory-mapped worker daemons are restarted. Follow the specific procedures for your operating environment.
1. Ubuntu and Debian Systems (APT & Ondřej Surý PPA)
Most modern production Linux servers run Debian or Ubuntu using either native repository packages or the widely adopted Ondřej Surý PPA repository.
Run the package update sequence via terminal SSH:
# Refresh package index
sudo apt update
# Inspect available PHP package updates
apt list --upgradable | grep -E "php(8\.[2-5])?"
# Perform targeted PHP upgrade
sudo apt install --only-upgrade php8.2 php8.2-fpm php8.2-cli \
php8.3 php8.3-fpm php8.3-cli \
php8.4 php8.4-fpm php8.4-cli
# Force restart PHP-FPM worker daemons
sudo systemctl restart php8.2-fpm || true
sudo systemctl restart php8.3-fpm || true
sudo systemctl restart php8.4-fpm || true
# Reload reverse proxy / web server
sudo systemctl reload nginx
sudo systemctl reload apache22. RHEL, Rocky Linux, AlmaLinux & Fedora (DNF / Remi Repository)
Enterprise Linux environments utilizing the Remi repository must refresh metadata and pull the latest patched builds:
# Clean metadata cache and update PHP packages
sudo dnf clean metadata
sudo dnf check-update | grep php
# Apply updates to active PHP modules
sudo dnf upgrade "php*"
# Restart PHP-FPM service
sudo systemctl restart php-fpm
# Verify running process reflects new binary
sudo systemctl status php-fpm --no-pager3. cPanel & WHM Server Environments (EasyApache 4)
cPanel & WHM environments run isolated PHP packages managed under EasyApache 4 (ea-php*). cPanel released synchronized security patches across all supported ea-php channels on October 21, 2026.
Server administrators should log in via SSH as root and execute:
# Check and upgrade EasyApache 4 PHP packages
yum clean all
yum update "ea-php*" -y
# Restart cPanel web services and PHP-FPM pools
/scripts/restartsrv_apache
/scripts/restartsrv_cpanel_php_fpm
# Loop through all running ea-php FPM daemons to force reload
for fpm in $(systemctl list-unit-files | grep ea-php | awk '{print $1}'); do
systemctl restart "$fpm"
doneFor administrators without root SSH access, navigate to WHM > EasyApache 4 and confirm that all package components reflect the latest maintenance releases.
4. Docker and Kubernetes Container Deployments
Patching the host machine does not protect containerized PHP applications. Container images package their own compiled PHP runtime binaries, which remain vulnerable until explicitly rebuilt with updated base images.
Update your Dockerfile base image references to the exact patched patchlevel tags:
# ❌ VULNERABLE: Pinning to older sub-minor releases
# FROM php:8.3.35-fpm-alpine
# ✅ SECURE: Pinning to patched upstream release
FROM php:8.3.36-fpm-alpine
# Set defensive memory limits
RUN echo "memory_limit = 512M" > /usr/local/etc/php/conf.d/security.ini \
&& echo "post_max_size = 32M" >> /usr/local/etc/php/conf.d/security.iniTrigger a fresh image rebuild without utilizing local layer cache:
# Force Docker to pull newest upstream base layers
docker compose build --no-cache --pull app
docker compose up -d --force-recreate app
# For Kubernetes clusters: roll out new image deployment
kubectl set image deployment/php-api php-worker=registry.example.com/php-api:8.3.36-v2
kubectl rollout status deployment/php-apiHow to Verify Active Runtimes in Memory
A common operational error is verifying the PHP version solely via CLI (php -v) while the actual web worker continues running an older, unpatched binary cached in memory.
Step 1: Verify the CLI Binary
php -vEnsure the output matches or exceeds 8.2.35, 8.3.36, 8.4.27, or 8.5.12.
Step 2: Verify the Web Worker (PHP-FPM)
Query the running PHP-FPM daemon directly using its process status:
# Query the live binary linked to PHP-FPM
php-fpm8.3 -v
# Inspect the loaded binary location of active worker processes
sudo ls -l /proc/$(pgrep -f "php-fpm: pool" | head -n 1)/exeAlternatively, create a temporary, authenticated diagnostics endpoint in your web application (or run phpinfo() within an internal management route) to confirm the Core PHP Version loaded by your web server matches the patched release. Remove the script immediately after testing to avoid leaking system configurations.
Edge Defense: Cloudflare WAF & Cloud Armor Mitigations
While patching the core PHP interpreter is the only permanent solution, edge firewalls and Web Application Firewalls (WAF) provide indispensable frontline defense while maintenance windows are scheduled.
[ Incoming Malicious Request ]
|
v
+---------------------------------------------+
| Edge WAF (Cloudflare / Cloud Armor) |
| Inspects multipart boundaries & headers |
+---------------------------------------------+
/ \
[Exploit Signature] [Legitimate Traffic]
/ \
v v
+---------------------+ +---------------------+
| Blocked at Edge | | Forwarded to Origin |
| (403 Forbidden) | | PHP Runtime Host |
+---------------------+ +---------------------+Cloudflare WAF: Full Transaction Detection
Standard WAF inspection rules typically analyze incoming HTTP request headers and initial body bytes. Because attackers can manipulate multipart chunk boundaries across multiple TCP packets to conceal OOM triggers, Cloudflare deployed Full Transaction Detection rules.
- Managed Rule IDs: Enable Cloudflare Managed Rulesets covering
PHP Core - Remote Code Execution (CVE-2026-109618, CVE-2026-109619). - Action: Set the rule action to Block rather than Log or Challenge.
- False Positive Management: Cloudflare’s full transaction engine correlates origin response codes (such as unexpected 500 Out-of-Memory responses following large multipart POST requests) with request byte signatures to neutralize exploit sequences without breaking legitimate file uploads.
Google Cloud Armor Custom Security Rule
For workloads deployed behind Google Cloud External Application Load Balancers, implement a Cloud Armor security policy rejecting abnormally formatted multipart requests exceeding normal application boundaries:
gcloud compute security-policies rules create 1000 \
--security-policy=sec-policy-production \
--expression="request.headers['content-type'].lower().startsWith('multipart/form-data') && request.headers['content-length'].asNumber() > 33554432" \
--action=deny-403 \
--description="Block abnormally large multipart uploads to mitigate PHP2Shell vectors"Temporary Interim Workarounds for Legacy Stacks
If an immediate runtime upgrade is blocked by legacy codebase dependencies, implement these four interim hardening measures to restrict exploitation surfaces:
- Reduce
post_max_size: Lower the maximum acceptable POST request size inphp.inito reduce the parser’s capacity to allocate large contiguous heap segments:post_max_size = 16M upload_max_filesize = 16M - Elevate or Disable
memory_limitBailouts for Critical Paths: Because CVE-2026-109618 requires an out-of-memory error to trigger the uninitializedlongjmp()bailout, raisingmemory_limit(or temporarily settingmemory_limit = -1in isolated environments with sufficient server RAM) prevents the fatal allocation tripwire from firing under crafted payloads. - Restrict File Upload Paths: If your web application does not require public file uploads, disable uploads globally in
php.ini:file_uploads = Off - Deploy Process Recyclers in PHP-FPM: To mitigate CVE-2026-109619’s use-after-free persistence across worker lifespans, configure PHP-FPM to terminate and respawn workers after a minimal number of requests:
Respawning worker processes every 100 requests purges stale global heap addresses before complex exploit chains can stabilize.; In /etc/php/8.x/fpm/pool.d/www.conf pm.max_requests = 100
Frequently Asked Questions
What is the root cause of the PHP2Shell vulnerabilities?
PHP2Shell consists of CVE-2026-109618 and CVE-2026-109619, rated CVSS 9.2 Critical. Both stem from PHP core memory management during abrupt execution termination. When memory limits or fatal errors are encountered, PHP calls the C standard library function longjmp() to bypass normal call stack unwinding. In CVE-2026-109618, multipart upload parsing leaves request memory uninitialized before longjmp(), which shutdown handlers misinterpret as valid pointers. In CVE-2026-109619, global engine state retains pointers to freed request memory, causing a use-after-free vulnerability across successive worker requests.
Which PHP versions are vulnerable and which releases contain the fix?
All active PHP branches prior to the emergency security release on October 21, 2026, are affected. The patched versions are PHP 8.2.35, PHP 8.3.36, PHP 8.4.27, and PHP 8.5.12. End-of-Life branches (PHP 5.4 through 8.1) are inherently vulnerable by design but do not receive upstream security patches from the PHP Foundation; they require commercial extended support backports or compensatory WAF isolation.
Why is restarting web server and PHP-FPM worker pools mandatory after patching?
Upgrading the PHP binary or shared libraries on disk does not immediately alter worker processes already running in memory. Long-running daemons like PHP-FPM, Apache mpm_event, and FrankenPHP hold active memory maps of the vulnerable libphp or php-fpm executables. Until you run systemctl restart php*-fpm or reload web services, existing workers remain fully vulnerable to unauthenticated remote code execution.
Can Cloudflare WAF or cloud firewall rules replace patching the PHP runtime?
No. While Cloudflare WAF, Google Cloud Armor, and AWS WAF offer vital edge protection by intercepting known multipart exploit signatures using full transaction detection, edge filters are strictly temporary compensatory controls. Subtle variations in HTTP chunking, multipart boundary encoding, or compression can bypass edge rules. Updating the underlying PHP runtime is the only definitive fix.
How can administrators mitigate PHP2Shell on End-of-Life (EOL) PHP servers?
On unpatched legacy environments (such as PHP 7.4 or 8.0), administrators should temporarily set memory_limit = -1 in php.ini to prevent OOM bailout triggers, sharply reduce post_max_size to restrict multipart parsing buffers, enforce strict WAF inspection, or acquire backported patches through enterprise extended lifecycle providers like TuxCare.
Need Expert Security Hardening for Your Web Infrastructure?
Whether managing complex microservices, high-traffic Laravel backend architectures, or multi-region cloud servers, our enterprise consultancy audits infrastructure postures and automates zero-day vulnerability responses.




