October 21, 2026
PHP 0day: CVE-2026–109618 / CVE-2026–109619 Mitigation
What to know, what to do, and how to detect exploitation — before the patch drops.

By Muhammad Sameer
4 min read
The Situation
A pre-patch heap use-after-free in PHP's session.upload_progress handler is publicly disclosed. The bug is reachable on stock PHP configurations — no special settings, no authentication, no unusual application code. A single multipart POST can trigger it, and the exploitation path leads to zend_call_function → system(), i.e. remote code execution.
Vendor severity is CVSS v4.0: 9.2 (Critical). The coordinated patch is scheduled for 2026–10–21 at 14:00 UTC (7:00 PM PKT). Until then, every PHP 8.x deployment on default settings is potentially exposed.
What Makes This Different
Most PHP 0-days require specific application behavior (a vulnerable framework, a misconfigured upload endpoint, a specific CMS plugin). This one doesn't.
- Affected component:
ext/session/session.c— thephp_session_rfc1867_callbackfunction - Reachable by: any endpoint that accepts
multipart/form-data - Required config:
session.upload_progress.enabled = On(the default) - Authentication: none
- Impact: RCE via
system()
The bug lives in PHP core, not in userland. That means every PHP application — WordPress, Laravel, Drupal, custom apps, APIs — is a potential vector if it accepts file uploads.
The Vulnerable Code
php_session_rfc1867_callback caches two raw zval * pointers into live HashTables:
zval *post_bytes_processed;
zval *current_file_bytes_processed;zval *post_bytes_processed;
zval *current_file_bytes_processed;These point into the session's internal progress array. On the second update cycle, the array is freed and re-decoded — but the cached pointers are never refreshed. They now point into freed memory. When the request continues writing through them, the write lands in attacker-controllable heap memory.
The PoC reclaims the freed chunk with attacker-shaped data that looks like a zend_internal_function and a zend_fcall_info, steers execution to zend_call_function, and calls system() with an attacker-supplied command.
Who Is Affected
VersionPatchedNotesPHP 8.5.x8.5.11Current stablePHP 8.4.x8.4.26Current stablePHP 8.3.x8.3.35Current stablePHP 8.2.x8.2.34Last patch for 8.2 (EOL branch)PHP 8.0 / 8.1No fixEOL — migrate or isolatePHP 7.xNo fixEOL — migrate or isolatePHP 5.xNo fixEOL — migrate or isolate
If you are running PHP 5, 6, or 7, you will not receive a patch. The only options are to migrate or to disable the vulnerable feature and isolate the host from the internet.
Immediate Mitigation (Do This Now)
1. Disable session.upload_progress
In php.ini, .user.ini, or your virtual host config:
session.upload_progress.enabled = Offsession.upload_progress.enabled = OffReload PHP-FPM:
systemctl reload php8.2-fpm
# or
systemctl reload php8.3-fpmsystemctl reload php8.2-fpm
# or
systemctl reload php8.3-fpmVerify:
php -i | grep "session.upload_progress.enabled"
# Expected: session.upload_progress.enabled => Off => Offphp -i | grep "session.upload_progress.enabled"
# Expected: session.upload_progress.enabled => Off => OffThis is the single most effective stopgap. It closes the documented path in under two minutes.
2. Block Multipart POSTs to Endpoints That Don't Need Uploads
The bug lives in the multipart parser, which runs before the session.upload_progress setting is even consulted. Add a WAF / reverse proxy rule:
Nginx:
location ~* \.php$ {
if ($http_content_type ~* "multipart/form-data") {
return 403;
}
}location ~* \.php$ {
if ($http_content_type ~* "multipart/form-data") {
return 403;
}
}(Apply only where uploads are not legitimately expected.)
ModSecurity:
SecRule REQUEST_HEADERS:Content-Type "@contains multipart/form-data" \
"id:100001,phase:1,deny,status:403,msg:'Multipart blocked'"SecRule REQUEST_HEADERS:Content-Type "@contains multipart/form-data" \
"id:100001,phase:1,deny,status:403,msg:'Multipart blocked'"3. Rate-Limit Multipart Requests
Even on legitimate upload endpoints, throttle multipart POSTs per IP:
limit_req_zone $binary_remote_addr zone=upload:10m rate=5r/m;
location /upload {
limit_req zone=upload burst=3 nodelay;
}limit_req_zone $binary_remote_addr zone=upload:10m rate=5r/m;
location /upload {
limit_req zone=upload burst=3 nodelay;
}4. Harden PHP-FPM
Even if an attacker achieves RCE, keep the blast radius small:
; /etc/php/8.2/fpm/pool.d/www.conf
php_admin_value[open_basedir] = /var/www/html:/tmp
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen
php_admin_value[allow_url_fopen] = Off; /etc/php/8.2/fpm/pool.d/www.conf
php_admin_value[open_basedir] = /var/www/html:/tmp
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen
php_admin_value[allow_url_fopen] = Offopen_basedir is the highest-value containment control. disable_functions stops the trivial system() call but does not stop a full exploit — the attacker can call other syscalls directly.
Detection
Log Sources
SourceWhat to Look ForPHP-FPM error logSIGSEGV, worker exited on signal 11Kernel log (journalctl -k)php-fpm[PID]: segfault at ... in libc.soWeb access logPOST + multipart/form-data to .php endpoints not expected to receive uploadsWAF403s on the multipart block rule — indicates scanning or attackAppArmor / SELinuxDENIED events where php-fpm attempts to read /etc/passwd or spawn a shell
Failed Attempt = Worker Crash
A successful exploit requires the exact memory offsets for the target PHP build. A failed attempt crashes the PHP-FPM worker. This is valuable: repeated segfaults from a single client IP are an exploitation attempt in progress.
# Watch for this pattern
journalctl -u php8.2-fpm -f | grep -i "segfault\|signal 11"# Watch for this pattern
journalctl -u php8.2-fpm -f | grep -i "segfault\|signal 11"If you see it, block the source IP immediately and preserve logs.
Session File Anomalies
The PoC creates session files keyed upload_progress_*. A sudden spike in these files — especially from a single IP — indicates probing:
ls -lt /var/lib/php/sessions/ | grep upload_progress | headls -lt /var/lib/php/sessions/ | grep upload_progress | headeBPF / Falco Rule
Detect post-exploitation command execution from a PHP worker:
- rule: PHP-FPM spawning shell
desc: Detects command execution from PHP-FPM worker
condition: spawned_process and proc.pname = "php-fpm" and proc.name in ("sh", "bash", "dash")
output: "PHP-FPM spawned shell (user=%user.name cmd=%proc.cmdline)"
priority: CRITICAL- rule: PHP-FPM spawning shell
desc: Detects command execution from PHP-FPM worker
condition: spawned_process and proc.pname = "php-fpm" and proc.name in ("sh", "bash", "dash")
output: "PHP-FPM spawned shell (user=%user.name cmd=%proc.cmdline)"
priority: CRITICALThe Patch
When the patch drops at 14:00 UTC, upgrade immediately:
# Debian / Ubuntu
apt update && apt upgrade php8.2 php8.2-fpm php8.2-cli
# RHEL / AlmaLinux
dnf update php-fpm php-cli
# LiteSpeed lsphp
/usr/local/lsws/admin/misc/lsup.sh -f -v 8.2.34# Debian / Ubuntu
apt update && apt upgrade php8.2 php8.2-fpm php8.2-cli
# RHEL / AlmaLinux
dnf update php-fpm php-cli
# LiteSpeed lsphp
/usr/local/lsws/admin/misc/lsup.sh -f -v 8.2.34Verify:
php -v
# Expected: PHP 8.2.34 ...php -v
# Expected: PHP 8.2.34 ...Do not delay. The window between public disclosure and mass exploitation is shrinking. For a CVSS 9.2 RCE with a public PoC, that window is measured in hours, not days.
What This Means Beyond Today
This 0-day is a reminder of a few structural realities:
- PHP core bugs reach every PHP application. Unlike framework or CMS vulnerabilities, they cannot be fixed at the application layer.
- Default configurations are not safe configurations.
session.upload_progress.enableddefaults toOnfor a feature most applications don't need. Disabling unused features is a baseline hardening step, not a nice-to-have. - EOL branches are permanent exposure. PHP 5, 6, and 7 will not receive a fix. Organisations still on these branches are exposed indefinitely — and this 0-day will not be the last.
- Containment buys time.
open_basedir,disable_functions, AppArmor profiles, and read-only filesystems do not prevent exploitation — but they limit what an attacker can do after. - Detection matters as much as prevention. A crashed worker from a failed exploit attempt is the earliest signal you will get. Monitor for it.
Summary
- Vulnerable: PHP 8.x on default
session.upload_progressconfig - Impact: Unauthenticated RCE
- Stopgap:
session.upload_progress.enabled = Off - Patch ETA: 2026–10–21, 14:00 UTC
- Detection: PHP-FPM segfaults + anomalous multipart traffic
- EOL branches: No fix — migrate or isolate
If you manage PHP infrastructure, act now. The mitigation takes minutes. The exploitation window is hours.
If you're working on this — whether on the defender side, in a SOC, or tracking the advisory — I'm documenting response patterns and happy to compare notes. Reach out.
#PHP #CyberSecurity #0day #RCE #InfoSec #AppSec