Full RCE exploit chain for two critical PHP vulnerabilities in the multipart parser and session upload progress handler, plus three bypass exploits that defeat the official security patch (PHP 8.4.27) and all recommended mitigations. Core exploits: - CVE-2026-109618: OOM in multipart parser → session persistence → LFI → RCE - CVE-2026-109619: Session poisoning via upload progress (direct + race) → RCE - WordPress-targeted wrapper with LFI auto-detection Patch bypass exploits (confirmed RCE on PHP 8.4.27): - Race condition: TOCTOU inherent to upload progress feature design - RLIMIT_AS: mmap() failure bypasses the patched OOM handler - /proc/PID/fd: temp file inclusion bypasses ALL mitigations
4.2 KiB
PHP 8.4.27 Patch Bypass Findings
Summary
The PHP security patch released 2026-10-21 (PHP 8.4.27, 8.3.36, 8.2.35, 8.5.12) for CVE-2026-109618 and CVE-2026-109619 has three confirmed bypass paths that achieve Remote Code Execution on fully patched systems.
The advisory's recommended mitigation session.upload_progress.enabled=0 blocks
two of the three bypasses but is itself defeated by the third.
Bypass #1: Race Condition (TOCTOU)
File: race_bypass_patched.py
Confirmed RCE: Yes, first attempt
Patches bypassed: PHP 8.4.27 OOM fix
Mitigations bypassed: session.upload_progress.cleanup=1
The session upload progress feature writes attacker-controlled data to the session
file on disk during the multipart upload. Cleanup only runs at MULTIPART_EVENT_END.
A concurrent LFI request can race to include the session file while the upload is
still in progress.
This is a TOCTOU (Time-of-Check-Time-of-Use) issue inherent to the feature's design — the data must exist on disk for the feature to work, creating a window that cannot be eliminated without removing the feature.
Blocked by: session.upload_progress.enabled=0
Bypass #2: RLIMIT_AS / mmap() Failure
File: rlimit_bypass_patched.py
Confirmed RCE: Yes
Patches bypassed: PHP 8.4.27 OOM fix (different code path)
Mitigations bypassed: Standard memory_limit-based OOM handling
The patch intercepts OOM from PHP's memory_limit (via zend_mm allocator).
When memory_limit=-1 and the OS enforces address space limits via RLIMIT_AS
(or cgroup memory.max), mmap() fails through a different code path that
the patch does not cover.
- Worker exits with code 1 (not the patched exit code 70)
- Session file persists on disk with attacker-controlled PHP code
- New worker spawns → LFI includes poisoned session → RCE
Relevant in production:
- Docker/k8s containers with cgroup memory limits
- Shared hosting with per-tenant RLIMIT_AS
- Admins using
memory_limit=-1trusting OS-level limits
Blocked by: session.upload_progress.enabled=0
Bypass #3: /proc/PID/fd Temp File Inclusion
File: procfd_bypass_hardened.py
Confirmed RCE: Yes, first attempt
Patches bypassed: ALL patches
Mitigations bypassed: ALL mitigations including upload_progress=0
During a multipart file upload, PHP creates a temporary file with attacker-
controlled contents. This file is visible via /proc/<pid>/fd/<N> to any
process that can read procfs. A concurrent LFI request from a different FPM
worker can include this file directly.
This attack does NOT use session poisoning at all — it bypasses every session-related mitigation.
Blocked by:
- Fixing the LFI vulnerability
hidepid=2on /proc mount (hides other processes' FDs)open_basedirrestricting /proc access- Disabling file uploads entirely (impractical)
Mitigation Effectiveness Matrix
| Mitigation | Race | RLIMIT | /proc/fd |
|---|---|---|---|
| PHP 8.4.27 patch alone | FAIL | FAIL | FAIL |
| + upload_progress=0 | OK | OK | FAIL |
| + hidepid=2 on /proc | FAIL | FAIL | OK |
| + upload_progress=0 + hidepid | OK | OK | OK |
| Fix the LFI | OK | OK | OK |
Tested Vectors That Did NOT Bypass the Patch
- Multipart part header flood: OOM triggered but the patch handles it correctly (exit code 70, session file cleaned up)
- WAF bypass via PUT/PATCH: Passes POST-only WAF rules but PHP's
session.upload_progressonly fires on POST requests - Content-Type comma tricks: Pass WAF matching but PHP doesn't parse as multipart/form-data
- Access log poisoning: Works conceptually but fragile (previous log entries may cause PHP parse errors)
Recommendations
- Immediate: Set
session.upload_progress.enabled=0in php.ini - Immediate: Mount /proc with
hidepid=2(orhidepid=invisibleon newer kernels) - Critical: Fix any Local File Inclusion vulnerabilities in applications
- Defense in depth: Set
open_basedirto restrict filesystem access - Do NOT rely on the patch alone — it leaves two bypass paths open