Updating to PHP 8.2.35, 8.3.36, 8.4.27, or 8.5.12 fixes the engine's out-of-memory corruption and stale worker state, and CISA placed both CVEs on the KEV catalog with an October 29 federal deadline. What stood out to me in the post-patch testing from Abstract Security is that patched hosts still leave session.upload_progress.enabled = 1 on by default, turning any postponed local file inclusion (LFI) bug into an unauthenticated two-request RCE.
Vulnerability vs. Post-Patch Exposure Matrix
| Vector / Mechanism | CVE-2026-109618 (longjmp OOM) |
CVE-2026-109619 (Stale Worker State) | Session Upload Progress LFI-to-RCE |
|---|---|---|---|
| Execution Boundary | Pre-script (php_request_startup) |
Cross-request (PHP-FPM / mod_php worker) |
Request startup multipart parsing (RFC1867) |
| Affected Versions | PHP 5.4 – 8.5 (unpatched) | PHP 5.4 – 8.5 (unpatched) | All versions (including patched 8.2.35–8.5.12) |
| Fixed by Oct 2026 Patch? | Yes (8.2.35, 8.3.36, 8.4.27, 8.5.12) |
Yes (8.2.35, 8.3.36, 8.4.27, 8.5.12) |
No (enabled by default in php.ini) |
App-Level ini_set() Fix? |
Ineffective (triggers before script) | Ineffective (triggers during shutdown/reuse) | Ineffective (PHP_INI_PERDIR stage only) |
| Primary Mitigation | Upgrade binary / backport engine patch | Upgrade binary + reduce pm.max_requests
|
Set session.upload_progress.enabled = 0 in php.ini
|
1. Pre-Script Execution via longjmp() Cleanup
In unpatched versions (5.4 through 8.5), CVE-2026-109618 triggers when an out-of-memory error forces a longjmp() bailout while internal request structures are only partially initialized. During request shutdown, PHP's cleanup routine trusts those uninitialized pointers before a single line of application code runs, while CVE-2026-109619 leaves freed request pointers alive in global state for the next request on the same PHP-FPM or mod_php worker.
Why application WAFs miss it: Because the fault happens inside
php_request_startup()during multipart or query parsing, framework middleware, PHP-level authentication guards, and userland input sanitizers never execute.
2. Why ini_set() and Upload Progress Tweaks Fail
Setting session.upload_progress.enabled=0 inside application code (ini_set()) does nothing against the engine CVEs or session creation because multipart parsing happens during the PHP_INI_PERDIR / SYSTEM initialization phase before the script starts.
Even on freshly patched 8.2.35+ servers, an attacker can pass a chosen PHP_SESSION_UPLOAD_PROGRESS field in a multipart POST request alongside a custom PHPSESSID cookie to write an unsanitized filename payload directly into /var/lib/php/sessions/sess_<id> on disk. If your codebase has a dormant include($_GET['page']) style LFI, racing a concurrent read against that active upload executes arbitrary code even when session.use_strict_mode = 1 is enabled.
| Configuration Directive | Default Value | Hardened Value | Config Scope (Changeable) |
Security Impact |
|---|---|---|---|---|
session.upload_progress.enabled |
1 (On) |
0 (Off) |
PHP_INI_PERDIR (php.ini / .user.ini / FPM pool) |
Stops unauthenticated creation of /var/lib/php/sessions/sess_* via multipart POST |
session.use_strict_mode |
0 (Off) |
1 (On) |
PHP_INI_ALL (best in php.ini) |
Rejects uninitialized session IDs passed via cookies by normal session handlers |
max_input_vars |
1000 |
1000 |
PHP_INI_PERDIR |
Caps hash table collisions and multipart variable exhaustion |
post_max_size |
8M |
8M (or stricter at proxy) |
PHP_INI_PERDIR |
Limits memory allocation spikes during pre-script body parsing |
3. Lock Down the Parser Boundary and Verify Builds
First, verify your active PHP-FPM or CLI build date and patch level rather than trusting package manager cache headers:
php -v
php -i | grep -E "session.upload_progress.enabled|session.use_strict_mode|max_input_vars"
Next, disable upload progress at the system php.ini level so session files cannot be used as an unauthenticated staging ground:
; /etc/php/8.3/fpm/php.ini - must be set at the INI or pool level, not runtime
session.upload_progress.enabled = 0
session.use_strict_mode = 1
max_input_vars = 1000
post_max_size = 8M
Optional: Lock down via PHP-FPM Pool Config & Nginx Body Limits (Click to expand)
If you run multi-tenant PHP-FPM pools and want to make sure developers cannot re-enable upload progress via .user.ini or .htaccess, enforce php_admin_flag inside /etc/php/8.3/fpm/pool.d/www.conf:
php_admin_flag[session.upload_progress.enabled] = off
php_admin_flag[session.use_strict_mode] = on
php_admin_value[max_input_vars] = 1000
At the reverse-proxy boundary (Nginx/Caddy), cap request body sizes before payloads ever reach the FastCGI socket:
# nginx.conf / site block
client_max_body_size 8m;
client_body_buffer_size 128k;
For teams triaging exposure across legacy 7.4–8.1 backports and newer runtimes, we map emergency advisories, severity decisions, and response workflows in our xSypher product security runbooks alongside our verification standards.
Are you backporting the minimal source patches for EOL PHP 7.4/8.1 runtimes in production, or isolating legacy workers behind strict reverse-proxy body limits until you can upgrade?

Top comments (0)