Publication Date: October 23, 2026
Vector:CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Official Tracking: CVE-2026-109618 (GHSA-w8hw-w9fx-j79w) & CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp)
Authoritative Advisories: PHP Project Security Advisory (October 21, 2026), Ubuntu Security Notice USN-8948-1, Red Hat Security Bulletin RHSB-2026-013
On October 21, 2026, the PHP development team published coordinated emergency security updates addressing two critical vulnerabilities in the core PHP runtime: CVE-2026-109618 and CVE-2026-109619. Collectively referred to by security researchers as PHP2Shell, both vulnerabilities carry a CVSS v4.0 score of 9.2. Depending on the Server API (SAPI) architecture, process model, and runtime configuration, these memory-safety defects allow unauthenticated remote code execution (RCE) and process-memory leakage within web-serving environments.
Unlike application-layer defects (such as SQL injection, insecure deserialization, or logic flaws in CMS plugins), PHP2Shell resides within the C-based Zend Engine runtime. Under specific deployment architectures—most notably Apache mod_php—demonstrated attack paths execute during request startup and multipart ingestion before application routing, userland middleware, or application-level web application firewall (WAF) plugins evaluate the incoming request.
Applying a verified upstream release or a distribution-maintained backport is the only complete remediation. This guide provides an SRE-grade architectural breakdown of the failure modes, evaluates exposure across PHP SAPIs, and outlines verified patching and defense-in-depth procedures.
1. Executive Summary & Verified Version Matrix
The vulnerability profile differs across the two CVE identifiers:
- CVE-2026-109618 (OOM Cleanup Corruption): Triggered when an out-of-memory (OOM) condition interrupts request processing during initialization or early parsing. The engine's non-local error bailout skips state-rollback routines, leaving request-level structures partially constructed. Teardown cleanup routines subsequently evaluate this uninitialized memory as valid, leading to memory corruption.
- CVE-2026-109619 (Stale Global State / Cross-Request UAF): Triggered when request-scoped internal state persists inside global variables of a long-lived worker process after the request-scoped memory has been freed. A subsequent request handled by the same worker reuses these dangling pointers before normal reinitialization clears them, producing a Use-After-Free (UAF) condition.
Upstream Releases vs. Linux Vendor Package Backports
Linux distributions backport security fixes into existing minor package versions without rebasing the upstream version string. Do not evaluate vulnerability status by comparing php -v output to upstream numbers alone. Always cross-reference the package manager version against the vendor security notice.
| PHP Branch / Distribution | Upstream Support Status | Upstream Fixed Release | Distribution Fixed Package Version | Action Required |
|---|
| PHP 8.5 | Active Support | 8.5.12 | Distro-dependent | Upgrade upstream runtime or container base image |
| PHP 8.4 | Active Support | 8.4.27 | Distro-dependent | Upgrade upstream runtime or container base image |
| PHP 8.3 | Security Fixes Only | 8.3.36 | 8.3.6-0ubuntu0.24.04.13 (Ubuntu 24.04 LTS) | Update package via apt or rebuild container |
| PHP 8.2 | Security Fixes Only | 8.2.35 | Check vendor advisory (e.g., Red Hat RHSA-2026:87072) | Update package via package manager |
| PHP 8.1 | End-of-Life (EOL) | None (Minimal source backport) | 8.1.2-1ubuntu2.28 (Ubuntu 22.04 LTS) | Apply vendor package update via USN-8948-1 |
| Ubuntu 26.04 LTS | Active Support | N/A | 8.5.4-0ubuntu1.5 | Update system packages via USN-8948-1 |
| Ubuntu 26.10 | Active Support | N/A | 8.5.9-0ubuntu2.1 | Update system packages via USN-8948-1 |
| Legacy EOL (PHP 7.4, 8.0) | End-of-Life (EOL) | None (Minimal source backport) | Ubuntu Pro / ESM, Red Hat ELS | Verify vendor backport or migrate runtime |
2. Research Context and Coordinated Disclosure
The root memory-management vulnerabilities were discovered through coordinated research involving Calif (Ryan Austin) using GPT-5.6-Sol under OpenAI's "Patch the Planet" initiative, alongside independent vulnerability discovery and exploitability research by Wiz Research (Sagi Tzadik, Shir Tamari, Nir Ohfeld, and Tomer Schwartz). Technical write-ups and reproduction analyses were also published by Datadog Security Labs and Quarkslab.
Following private notification to the PHP security team in August 2026, maintainers across active branches coordinated core runtime fixes. After partial vulnerability references and candidate diffs surfaced publicly on October 20, the PHP development team accelerated disclosure, publishing official security updates across active branches on October 21, 2026 at 14:00 UTC. Following public disclosure, perimeter telemetry providers (including Cloudflare and Palo Alto Networks Unit 42) observed widespread automated scanning targeting exposed upload-progress and multipart endpoints.
3. Architectural Root-Cause Analysis
The vulnerabilities stem from how the Zend Engine manages memory allocation, exceptional control-flow aborts, and worker lifecycles.
========================================================================================
SIMPLIFIED REQUEST LIFECYCLE & SAPI FAILURE POINTS
========================================================================================
[ INCOMING HTTP REQUEST ]
│
▼
┌──────────────────────┐
│ sapi_activate() │ ◄── Early parsing (Headers, Query String, Multipart Bodies)
└──────────┬───────────┘
│
├───► [ CVE-2026-109618: OOM Startup Corruption ]
│ Allocation exceeds memory_limit mid-operation.
│ zend_bailout() uses longjmp() to escape execution frame.
│ State rollback skipped; partially initialized structures remain.
│ php_request_shutdown() cleans up uninitialized memory (Memory Corruption).
│
▼
┌──────────────────────┐
│ php_execute_script() │ ◄── Application Code (Frameworks, Custom Handlers, APIs)
└──────────┬───────────┘
│
├───► [ CVE-2026-109619: Stale Global State ]
│ Request 1 (Producer): Fatal error/abort triggers cleanup.
│ Request-scoped heap (emalloc) is freed back to allocator bins.
│ Persistent global references (e.g., PS(id)) are NOT cleared.
│ Request 2 (Consumer): Next request on same worker reuses stale pointer (UAF).
│
▼
┌───────────────────────┐
│ php_request_shutdown()│ ◄── SAPI teardown: frees request memory, resets buffers
└───────────────────────┘
========================================================================================
CVE-2026-109618: Out-of-Memory (OOM) Cleanup Corruption
PHP limits per-request memory utilization via memory_limit. When an allocation managed by the Zend Memory Manager (emalloc()) crosses this boundary, the engine calls zend_bailout(). In the C implementation, zend_bailout() relies on longjmp() to restore CPU register state and jump out of nested function calls directly to the outer request error handler.
The vulnerability occurs when this jump interrupts an in-progress data ingestion operation (such as RFC 1867 multipart form parsing):
- Incomplete Initialization: Internal data structures register structural counters or entry states before the underlying memory allocations for their contents have completed.
- Bypassed Rollback: When an allocation fails, the non-local
longjmp() bypasses the transactional error-handling logic that would ordinarily revert partially populated structures. - Corrupted Teardown: During request shutdown (
php_request_shutdown()), the engine iterates over registered structures, operating on the assumption that records flagged as active are valid. The cleanup routines read or dereference uninitialized memory or stale heap fragments, producing memory corruption that can be leveraged for remote code execution.
CVE-2026-109619: Stale Global State Across Request Lifecycles
In high-throughput environments, web servers avoid process-creation overhead by utilizing persistent worker pools (such as PHP-FPM or Apache prefork MPM). A single worker process serves multiple requests sequentially.
The Zend Engine enforces two distinct allocation tiers:
- Request-Scoped Allocations (
emalloc()): Sourced from pre-allocated memory slabs, reset and returned to the allocator at the end of each request. - Persistent Allocations (
pemalloc()): Sourced from system-level memory, surviving across multiple requests.
CVE-2026-109619 manifests as a lifetime desynchronization between request allocations and persistent globals:
- Producer Phase: A request encounters an abnormal termination (such as an OOM error, fatal abort, or diagnostic exit) while populating global state (such as session upload-progress tracking via
PS(id)). The request-scoped heap is wiped, but persistent engine globals retain references pointing into the freed memory region. - Consumer Phase: A subsequent request handled by that same worker reaches code paths that read the uncleared global before normal initialization resets it. The engine dereferences the dangling pointer (Use-After-Free), enabling controlled memory corruption or process-memory disclosure.
4. Server API (SAPI) Exposure Analysis
The attack surface of PHP2Shell is heavily dictated by the active Server API (SAPI) architecture:
========================================================================================
SAPI EXECUTION DIVERGENCE: APACHE mod_php vs. PHP-FPM
========================================================================================
[ CRAFTED HTTP MULTIPART REQUEST ]
│
▼
┌───────────────────────────────┐
│ Request Startup Ingestion │
│ (Header & Multipart Parsing) │
└───────────────┬───────────────┘
│
Allocation exceeds configured memory_limit
│
▼
┌───────────────────────────────┐
│ zend_bailout() Called │
│ (longjmp unwinds stack) │
└───────────────┬───────────────┘
│
┌──────────────────────────┴──────────────────────────┐
▼ ▼
┌──────────────────────────────────────┐ ┌──────────────────────────────────────┐
│ APACHE mod_php │ │ PHP-FPM │
├──────────────────────────────────────┤ ├──────────────────────────────────────┤
│ • Worker survives startup failure. │ │ • Worker child terminates at once │
│ • Invokes php_request_shutdown(). │ │ via _exit() on startup abort. │
│ • Cleanup traverses partially-built │ │ • Single-request pre-auth startup │
│ request structures (OOM UAF). │ │ exploit path is HALTED here. │
│ • IMPACT: Pre-authentication RCE │ │ • NOTE: Still susceptible if failure │
│ demonstrated before app code runs. │ │ occurs at application stage or via │
│ │ │ cross-request state (CVE-109619). │
└──────────────────────────────────────┘ └──────────────────────────────────────┘
| SAPI Environment | CVE-2026-109618 (OOM Corruption) | CVE-2026-109619 (Stale Global State) | Technical Assessment & Operational Risk |
|---|
Apache mod_php | Highest Demonstrated Risk | Demonstrated Vulnerable | Critical: Apache workers execute request shutdown even if request startup fails. Pre-authentication RCE was experimentally demonstrated before userland application code executed. |
| PHP-FPM (FastCGI) | Susceptible (Application-stage) | Demonstrated Vulnerable (Session path) | High: Early-startup single-request RCE is mitigated because FPM terminates the child worker upon startup failure. However, FPM is susceptible if OOM is reached during application execution, and persistent workers are exposed to multi-request stale-state reuse. |
| FrankenPHP | At-Risk Web SAPI | At-Risk Web SAPI | High: Explicitly identified by the PHP security team as an affected web-serving SAPI. Long-lived worker execution models require validation against specific application worker behaviors. |
| CGI (Common Gateway Interface) | Theoretically Vulnerable | Mitigated by Lifecycle | Medium: Ephemeral per-request processes prevent cross-request state persistence, mitigating CVE-2026-109619. Single-request OOM cleanup corruption remains theoretically reachable during request teardown. |
| Swoole / RoadRunner | Deployment-Dependent | Deployment-Dependent | High: Persistent application runtimes keep execution state in-memory across requests. Exposure must be assessed based on worker isolation and request reset boundaries. |
| CLI (Command Line) | Low Operational Risk | Not Applicable | Low: CLI binaries do not ingest untrusted HTTP network traffic and terminate after execution. (Note: Securing CLI does not protect web services running on the same host). |
5. Production SRE Remediation & Verification Playbook
Applying vendor-verified package updates or upstream builds and restarting affected workers is the only complete resolution.
Debian / Ubuntu Reference Inspection & Patching Script
The following script serves as an operational baseline for standard Debian and Ubuntu systems running package-managed PHP. It inventories common system packages, applies available updates, and targets active PHP worker services.
#!/usr/bin/env bash
# ==============================================================================
# Reference Audit & Remediation Script for CVE-2026-109618 & CVE-2026-109619
# Target: Ubuntu LTS / Debian Stable Environments
# ==============================================================================
set -euo pipefail
echo "===> [Step 1] Inventorying Common System PHP Packages..."
# Inventory installed packages across standard repository namespaces
INSTALLED_PKGS=$(dpkg-query -W -f='${binary:Package} ${Status} ${Version}\n' \
"php*-common" "php*-fpm" "php*-cli" "php*-cgi" "libapache2-mod-php*" 2>/dev/null \
| grep "install ok installed" || true)
if [ -z "${INSTALLED_PKGS}" ]; then
echo "[-] No standard system PHP packages detected via dpkg. Check containerized or custom runtimes."
exit 0
fi
echo "${INSTALLED_PKGS}"
echo "===> [Step 2] Updating Package Repositories..."
sudo apt-get update -y
echo "===> [Step 3] Applying Targeted Security Updates..."
# Target discovered packages explicitly without wildcards to avoid breaking dependencies
TARGET_PACKAGES=$(echo "${INSTALLED_PKGS}" | awk '{print $1}' | tr '\n' ' ')
echo "Upgrading packages: ${TARGET_PACKAGES}"
sudo apt-get install --only-upgrade -y ${TARGET_PACKAGES}
echo "===> [Step 4] Restarting Discovered Active PHP Services..."
# Restart only active PHP execution runtimes; avoid restarting unrelated proxies
for fpm_service in $(systemctl list-units --type=service --state=running --no-legend | awk '{print $1}' | grep -E "php.*fpm" || true); do
echo "Restarting active PHP-FPM service: ${fpm_service}"
sudo systemctl restart "${fpm_service}"
done
if systemctl is-active --quiet apache2; then
echo "Restarting Apache web server (mod_php)..."
sudo systemctl restart apache2
fi
echo "===> [Step 5] Post-Restart Service Validation..."
for fpm_service in $(systemctl list-units --type=service --state=running --no-legend | awk '{print $1}' | grep -E "php.*fpm" || true); do
if systemctl is-active --quiet "${fpm_service}"; then
echo "[+] Service ${fpm_service} is active and running."
else
echo "[!] CRITICAL: Service ${fpm_service} failed to restart." >&2
exit 1
fi
done
echo "[✓] Execution completed. Proceed to four-point verification."
The SRE Four-Point Verification Standard
A successful package install or service restart does not independently prove that production web traffic is secure. Validate the following four criteria:
- Package Version Verification: Confirm that the installed package version matches or exceeds the specific vendor advisory (e.g.,
8.1.2-1ubuntu2.28 on Ubuntu 22.04 LTS or 8.3.6-0ubuntu0.24.04.13 on Ubuntu 24.04 LTS). - Active SAPI Runtime Audit: Verify the binary actively executing HTTP requests. CLI verification (
php -v) is insufficient. Inspect the running web server runtime using administrative health checks or a temporary local diagnostic file:
<?php
// Place temporarily in local webroot, restrict to 127.0.0.1, and delete immediately after validation
phpinfo(INFO_GENERAL);
- Worker Process Replacement: Verify that all pre-patch worker processes were terminated and replaced by checking process start times (
ps -eo pid,lstart,cmd | grep -E "php-fpm|apache2"). - Application Health Smoke Tests: Run integration tests across authentication endpoints, file uploads, and session-dependent workflows to ensure configuration directives remain intact.
Containerized Infrastructure (Docker & Kubernetes)
Host-level updates do not patch container images. For containerized infrastructure:
- Update Base Images: Update Dockerfile references to patched base tags or immutable SHA256 digests:
FROM php:8.3.36-fpm-bookworm
- Rebuild Without Cache: Ensure intermediate build stages do not reuse stale runtime layers:
docker build --no-cache -t enterprise-app:v2.4.1 .
- Validate In-Image Runtime: Verify the binary inside the container artifact before deploying:
docker run --rm enterprise-app:v2.4.1 php -r 'echo PHP_VERSION . "\n";'
- Trigger Orchestrator Rollout: Execute a rolling restart in Kubernetes to terminate existing pods and ensure that newly spawned workers pull the verified image.
6. Stopgap Mitigations (Scope, Operational Trade-offs & Limitations)
If emergency patching cannot be executed immediately, apply the following configuration mitigations. These measures are partial risk reductions and do not replace runtime patching.
; ==============================================================================
; PHP2Shell Temporary Configuration Mitigations (Apply in active php.ini)
; ==============================================================================
; [Mitigation for CVE-2026-109619: Session Upload-Progress Path]
; Disables the early session upload progress tracking mechanism.
; Enforce in php.ini or FPM pool configuration before request parsing.
; Does NOT protect against fatal-error backtrace or OPcache type confusion vectors.
session.upload_progress.enabled = 0
; [Mitigation for CVE-2026-109619 on PHP 8.5 Environments]
; Disables persistent fatal error backtraces in executor globals.
; Supported and applicable only on PHP 8.5 installations.
fatal_error_backtraces = 0
; [Operational Worker Recycling on PHP-FPM]
; Tunes worker processes to recycle periodically, reducing long-term stale state persistence.
; Configure within FPM pool configuration (e.g., /etc/php/8.3/fpm/pool.d/www.conf):
pm.max_requests = 100
Operational Constraints of Workarounds
- The Trade-offs of
memory_limit = -1: The PHP security advisory notes that setting memory_limit = -1 can remove the controllable PHP-level OOM trigger for CVE-2026-109618. However, underlying system allocation failures (e.g., mmap exhaustion) can still trigger the vulnerable code path. Furthermore, removing this threshold allows large requests to consume physical server memory, increasing the risk of denial-of-service. If tested, pair this setting with Linux cgroup v2 memory ceilings (memory.max). Cgroup limits act as an availability containment boundary, not a code-level vulnerability fix. - Do NOT Enforce
RLIMIT_AS or RLIMIT_DATA: The PHP security team explicitly warns against using process-level operating system limits (ulimit -v or RLIMIT_AS/RLIMIT_DATA) as substitutes for memory_limit. These operating system limits induce the exact low-level allocation failures that trigger the vulnerable zend_bailout() execution path. - Worker Recycling (
pm.max_requests): Lowering pm.max_requests (such as setting it to 100 or 1) forces FPM workers to restart after serving the configured number of requests, reducing cross-request stale state persistence. This is an operational tuning choice that carries performance and latency overhead; it is not a validated complete fix for CVE-2026-109619 and does not mitigate single-request vulnerabilities. - Protocol-Aware Edge/WAF Validation: At the reverse proxy layer (Nginx, Cloudflare, AWS WAF, HAProxy), enforce protocol-aware inspection:
- Enforce strict request body size limits (
client_max_body_size) on routes that do not legitimately accept file uploads. - Enforce limits on multipart part counts, header counts per part, and parameter nesting depth.
- Do not issue blanket drop rules for requests lacking a Content-Length header; valid HTTP/2 and chunked-transfer HTTP/1.1 requests legitimately omit this header. Enforce total decoded payload thresholds instead.
7. Detection, Threat Hunting & Incident Response
Because exploitation occurs at the runtime engine level, standard application logs (such as CMS access logs) rarely provide meaningful context. Security teams must correlate web server error logs, PHP runtime logs, and operating system process telemetry.
1. Runtime Diagnostic Signatures (Investigative Signals)
The following events are investigative leads, not definitive indicators of compromise, as legitimate operational errors or resource exhaustion can also generate them:
- Startup Memory Exhaustion:
PHP Fatal error: Allowed memory size of X bytes exhausted (tried to allocate Y bytes) in Unknown on line 0
(The Unknown on line 0 signature indicates that memory exhaustion occurred during engine startup or header/body ingestion before script execution).
- Worker Process Crashes: Apache error logs recording segmentation faults or abnormal child terminations:
AH00052: child pid X exit signal Segmentation fault (11)
AH00052: child pid X exit signal Aborted (6)
- Memory Corruption Logs: System error streams recording
zend_mm_heap corrupted or abnormal worker churn rates in PHP-FPM pools.
2. Behavioral Host Monitoring (Process Trees)
Under normal operational conditions, web server service accounts (www-data, apache, nginx) should never execute interactive system shells or external network transfer utilities. Query your Endpoint Detection and Response (EDR) or Linux auditd logs for abnormal child process creation:
# Anomalous Process Execution Tree
/usr/sbin/apache2 -k start (euid: 33)
└── /bin/sh -c "whoami; id; uname -a"
└── /usr/bin/whoami
Linux auditd Rule Example (Configured for Debian/Ubuntu UID 33):
# Alert on execution of interactive shells by web service accounts (euid 33 for www-data)
-a always,exit -F arch=b64 -S execve -F euid=33 -k web_worker_shell
-a always,exit -F arch=b32 -S execve -F euid=33 -k web_worker_shell
(Note: Validate the target distribution's web service UID prior to loading rules; non-Debian environments frequently use different service accounts and UIDs, such as UID 48 for Apache on RHEL).
3. SRE Incident Response Sequence
If anomalous child process execution or memory corruption is identified on an internet-facing host:
- Network Containment: Isolate the affected host or container at the network boundary (via security group or firewall adjustments) while preserving volatile memory.
- Forensic Evidence Collection: Capture running memory and offload web server access logs,
/var/log/php*-fpm.log, and system audit logs before restarting or terminating instances. - Credential Invalidation: Because memory disclosure can expose environment variables and runtime secrets, treat database passwords, API tokens, and session signing keys handled by the affected worker pool as potentially compromised. Rotate all exposed credentials.
- Clean Reconstruction: Do not attempt in-place cleanup on a confirmed compromised instance. Rebuild and deploy workloads from clean, verified base images running patched PHP binaries.
- Post-Remediation Verification: Verify that patched binaries are active across all endpoints and monitor process trees for recurrent execution anomalies.
8. Authoritative References
- PHP Foundation: Today's PHP Security Release, and How We're Strengthening PHP Security (October 21, 2026).
- PHP Security Advisory (GitHub): RCE via OOM Corruption, GHSA-w8hw-w9fx-j79w (CVE-2026-109618).
- PHP Security Advisory (GitHub): RCE via Stale Global State, GHSA-6wmf-4rv5-p3rp (CVE-2026-109619).
- Canonical / Ubuntu Security Notice: USN-8948-1: PHP Vulnerabilities (October 21, 2026).
- Red Hat Product Security: RHSB-2026-013: Critical PHP Core Vulnerabilities (October 21, 2026).
- OpenAI Security: Patch the Planet: AI-Assisted Discovery and Coordinated Disclosure (October 2026).
- Wiz Research: PHP2Shell: Core Engine Flaws Enable Unauthenticated Remote Code Execution (October 21, 2026).