CVE-2026-109619·PHP vulnerability
PHP has various global state that temporarily points into request memory. In some scenarios, global state may not be correctly reset, or may be repopulated after being reset. The global state may then refer to request memory even after it has been freed. Subsequent requests may read or branch on this stale state before it is fully initialized. Multiple strategies can trigger this condition and produce remote code execution (RCE).
- Severity
- high
- Software
- PHP
- Fixed in
- 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 (per branch; PHP 8.1 and older are end-of-life, no official fix)
- Published
How likely is exploitation
FIRST's Exploit Prediction Scoring System puts the probability of this CVE being exploited in the next 30 days at 100% — among the highest-scoring CVEs ever published. EPSS is an independent forecast of exploitation, not a severity rating: it says nothing about how much damage a successful attack does, which is what a CVSS score measures.
How to fix this CVE
Update to the patched release for your branch — PHP 8.2.35, 8.3.36, 8.4.27 or 8.5.12 — the only complete fix. php.net: "there are no complete mitigations, updating is the only safe choice." If you cannot update immediately, the documented partial mitigation for THIS CVE is to set session.upload_progress.enabled=0 and restart every worker, applied BEFORE request parsing via php.ini, an FPM pool or server configuration. Do NOT rely on ini_set() or a per-directory .user.ini — they apply too late and a customer can override them. This reduces exposure but is not complete — and on PHP 8.5 there is a second confirmed trigger (the fatal_error_backtraces setting), so disabling upload_progress alone does not close it on 8.5. For versions with no official patch (PHP 5.4–8.1 are end-of-life), a community stopgap exists: Hosted Power's hp_uploadprogress_guard PHP extension (MIT, linked under References), which since v3 carries PHP's fixed multipart parser per branch behind a memory-headroom guard, mirrors the rest of the official fix component by component, and steps aside on a patched engine (8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 and newer) while keeping its non-php2shell fixes active. Since v3.2.0 it also isolates unserialize() re-entrancy (php-src#24481, still open upstream) and since v3.2.1 it carries PHP's approved fix for the SimpleXML crash that 8.4.27 and 8.5.12 introduced (php-src#24488). It covers PHP 5.4 through 8.5, which makes it the only route for end-of-life branches. Checked against the repository on 22 Oct 2026 (v3.2.2). It is a stopgap, not a replacement for upgrading. Note on the fixed releases, verified against php-src on 22 Oct 2026. Upgrading closes this CVE, but two distinct PHP bugs outlive it. php-src#24481 - a use-after-free in var_destroy() during unserialize() re-entrancy - is still OPEN and confirmed present in 8.5.12, 8.4.27, 8.3.36, 8.2.35 and 7.4.33, and it is reachable over HTTP through the same session machinery this CVE abuses (session.serialize_handler=php_serialize alongside upload-progress tracking), so the fixed release does not by itself close the session attack surface. php-src#24488 - a GC double-free of the SimpleXMLElement properties table that aborts the FPM worker on any request JSON-encoding a SimpleXMLElement caught in a collected cycle - was INTRODUCED by 8.4.27 and 8.5.12 (8.4.26 is unaffected); its fix landed in the PHP-8.4, PHP-8.5 and PHP-8.6 branches on 22 Oct 2026 but has not shipped in a release yet. Patch regardless: this CVE is remote code execution and a worker crash is not. Then track both issues.
sudo apk update && sudo apk upgrade php82 php82-fpm (match your version prefix), then sudo rc-service php-fpm82 restart. Confirm the patched build is in your release branch before relying on it.Defensia detects this vulnerability
ModSecurity 9910015 (inline, Apache with SecRequestBodyAccess On) - denies the known upload_progress exploit shape; Defensia agent v1.4.81+. Partial detector, not a complete block.weblog (relays the ModSecurity block; does not inspect bodies)What an exploitation attempt looks like
Sample log line indicative of exploitation attempts:
POST / HTTP/1.1 Content-Type: multipart/form-data; boundary=X — a part named PHP_SESSION_UPLOAD_PROGRESS drives the handler while the same PHPSESSID is replayed across two endpoints whose directories declare different session.serialize_handler values (php vs php_serialize), with a serialized-object payload in the upload filename, e.g. filename="|O:4:\"Evil\":1:{s:3:\"cmd\";s:2:\"id\";}". The access log shows only a multipart POST: the discriminating content is in the request body, which access logs do not record. Only an inline WAF with request-body access (Apache + ModSecurity, phase 2) can see it; a log-based engine cannot.WAF mitigation (if patching is not yet possible)
Add this rule to your WAF to block exploitation attempts while you schedule the patch.
This is the one path here a WAF can address: a ModSecurity rule (Apache, inline) that denies a multipart request driving PHP_SESSION_UPLOAD_PROGRESS while carrying a serialized object or PHP tag in a filename. (It does NOT address the companion CVE-2026-109618, whose trigger is memory exhaustion with no distinctive payload — see that advisory.)
SecRequestBodyAccess On
SecRule ARGS_NAMES "@streq PHP_SESSION_UPLOAD_PROGRESS" \
"id:2026109619,phase:2,deny,status:403,log,t:none,\
msg:'CVE-2026-109619 PHP upload_progress UAF/deserialization attempt',chain"
SecRule FILES_NAMES|ARGS:PHPSESSID "@rx (?i)(?:\|O:[0-9]+:|<\?php|php_serialize|<\?=)" "t:none"
Because 109619 is a memory-corruption/deserialization chain, a signature is a time-buying stopgap only. On nginx + php-fpm the body reaches PHP before a log-based engine sees it, so there the control is detection, not blocking — and php-fpm is itself vulnerable (php.net confirmed RCE on it), not just mod_php. Patch to the fixed release — that is the only reliable fix.How to check if you are affected
- Confirm your PHP version/branch: php -v and php-fpm8.x -v. 5.4.0–8.5.x before the release-day fix are affected.
- Check the handler state (ON by default): php -i | grep -i session.upload_progress.
- Look for directories that declare different session serializers (a precondition for the handler-mismatch chain): grep -rs 'session.serialize_handler' /etc/php* /var/www --include=.user.ini --include=php.ini 2>/dev/null — mixed php and php_serialize values across paths sharing one save_path is the risky layout.
- Grep the session save path for serialized objects or PHP tags: grep -rIl -e '<?php' -e 'O:[0-9]' $(php -r 'echo ini_get("session.save_path") ?: "/var/lib/php/sessions";') 2>/dev/null.
- Watch for php-fpm worker crashes/segfaults (dmesg, the FPM error log) around multipart POST bursts — a sign of the UAF being exercised — and for the web user spawning shells or writing new PHP files.
Indicators of compromise
- php-fpm worker segfaults or 'SIGSEGV' / 'child exited on signal 11' entries in the FPM error log correlated with multipart POSTs.
- Session files under the save path containing serialized object markers 'O:<n>:' or PHP open tags.
- The same PHPSESSID replayed across two endpoints with different session.serialize_handler settings.
- Multipart POSTs carrying PHP_SESSION_UPLOAD_PROGRESS with a body-supplied PHPSESSID rather than a cookie.
- Web user (www-data, nginx, apache, php-fpm) spawning sh/bash/curl/wget or new PHP files appearing under the web root after release day.
- Multipart/form-data POSTs immediately followed by PHP memory-limit errors or repeated HTTP 500 responses from the same endpoint (Wiz).
- Unexpectedly large or malformed PHPSESSID response cookies.
- Unexplained PHP-FPM worker churn — workers recycling or restarting with no obvious cause.
FAQ
How is this different from CVE-2026-109618?
They share the same upload_progress/multipart entry point and were disclosed together. 109618 is about session fixation and raw filename injection landing attacker content on disk; 109619 is the memory-safety and deserialization side — a heap use-after-free in var_destroy and a cross-request serializer leak that enables object injection. Patch both at once; the fixed PHP release closes both.
Is this only exploitable on Apache with mod_php?
No. The handler runs under FPM too; the public analysis confirms the serializer leak specifically in FPM. Reliability varies with SAPI and heap layout, but treat any PHP 5.4–8.5 deployment as affected until patched.
I'm on an EOL branch (7.x / 8.0 / 8.1). What now?
No official patch will be issued. Upgrade to a supported 8.2+ branch. A body-inspecting WAF (ModSecurity inline on Apache) is a stopgap; on nginx + php-fpm you get detection but not reliable blocking.
Does disabling upload_progress stop this one too?
It reduces exposure by closing the shared entry point, but PHP core developers are explicit that patching is the only complete mitigation. Use session.upload_progress.enabled = Off and session.use_strict_mode = On to buy time, then patch.
Can I detect exploitation attempts?
Yes — watch for php-fpm segfaults around multipart POST bursts, serialized objects or PHP tags appearing in session files, and the web user spawning shells. The detection steps above give the exact commands.
Related PHP CVEs
References
Track CVEs across your fleet automatically
Defensia scans your Linux servers and tells you exactly which ones are running vulnerable versions — including CVE-2026-109619. Free for 1 server.
Get started free