⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣤⣤⣤⣤⣤⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡾⠋⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⡇⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡿⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡎⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡇⢸⣿⠟⠉⠀⠀⠈⢻⣿⡿⠁⠀⠀⠈⢻⡟⢻⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣶⡦⠀⣇⣿⣦⡀⠙⠀⠠⡀⠀⠀⠀⠀⠀
⠀⠀⠀⠘⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⢸⡇⠀⠀⠀⠀⠀⣾⡿⣇⠀⠀⠀⠀⢸⡅⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠟⢀⣀⡈⠻⣿⣿⣿⣷⣄⠁⢄⠀⠀⠀⠀
⠀⠀⠀⠀⠘⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣷⣄⠀⠀⣀⣼⠃⠁⠘⣷⣄⣀⣠⣾⣷⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣷⣦⡈⠉⢹⣿⣿⣧⠈⢿⡇⠀⠀
⠀⠀⠀⠀⠀⠘⢿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢺⢿⣿⣿⣿⣿⣿⣿⠀⠀⠀⢸⣿⣿⣿⠿⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⢇⠀⣿⣿⣿⣿⣿⣿⠀⣆⣿⣿⡿⠃⠀⢁⠄⠀
⠀⠀⠀⠀⠀⠀⠈⢻⣿⣶⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠀⠀⠈⠻⣿⣿⣦⣿⣦⣼⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠂⠉⠻⢿⣿⣿⡿⠀⣿⡟⠉⢀⣀⣴⡟⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠙⣿⣿⣷⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣇⠀⠀⡈⢻⠋⡏⠛⢹⡇⠀⣴⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡇ ⠙⠋⣀⣤⣤⡄⠉⠉⠛⠛⠛⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣿⣿⣿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡀⠀⠁⠈⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠟⠋⠑⢤ ⠛⠋⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣿⣿⣿⣶⣄⠀⠀⠀⠀⠀⠀⠘⠻⣧⣄⣆⣰⣀⣲⣀⣦⣀⣤⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⠎⠁⠀⠀⠀⠀⠀⠈⠀⠒⠂⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣿⣿⣿⣷⣦⡀⠀⠀⠀⠀⠀⠙⢿⣿⣿⣿⣿⣿⠿⠋⠁⠀⠀⠀⠀⠀⠀⢀⣤⣠⠶⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀  ⠀⠈⠙⢿⣿⡈⠻⢷⣦⣄⠀⠀⠀⠀⠀⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⣀⣴⠿⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⢶⣄⠙⠻⢿⣶⣤⡀⠀⠀⠀⠀⠀⠀⠀⡀⠀⣀⣤⡶⠟⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠿⣦⣄⡈⠙⠻⢷⣦⣄⡀⠀⠀⢠⣴⣿⠿⠛⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠿⣷⣦⣄⠈⠙⠻⢷⣦⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⠿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
            ⠀⠀⠀⢀⣀⣀⣀⣠⣾⣧⣤⣤⣴⣶⣶⣶⣶⠦⠉⠻⢿⣷⣦⣄⣀⠉⠙⠛⠿⠿⢶⣶⣶⣤⣤⣤⣄⠀⢀⣠⣿⡏⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
            ⠀⠀⠀⠀⠻⠿⠿⠿⠛⠛⠛⠛⠻⠏⠉⠀⠀⠀⠀⠀⠀⠈⠙⠛⠿⢿⣷⣶⣤⣤⣀⣀⣀⡉⠉⠉⠁⣠⣶⣿⣿⣿⣶⣦⣤⣤⣼⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
                                       ⠉⠉⠛⠛⠿⠿⠿⠿⣧⠹⣿⣿⡟⠿⠿⠿⣿⣿⣿⣿⡏⠀⠀⠀
                                                    ⠀⠀⢀⣿⡟⠀⠀⠀⠀⠀⠀⠙⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
                                                ⠘⣷⣄⣀⣠⣾⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
                         ⠉⠉⠉
                                      
----------------------------
☆ Steal Everything         ☆
☆           Leave Nothing  ☆
----------------------------
EST. 2014-2026

PHP-UP-2026

PHP session.upload_progress UAF CVE-2026-109618 / CVE-2026-109619

phpup@C4b1NKr3W:~ [active]
[*] Stage: CVE-2026-109618 / -109619 (PHP session.upload_progress heap UAF)
[*] Author: J4ck3LSyN (ATLAS)
[>] language: python · Bug S: weaponized (lab) · Bug U: ARM/P1 confirmed, FIRE needs glibc 2.39 grooming

Overview

CORRECTED FINDINGS (2026-10-21): Cached-pointer chain DEAD at the addref (session.c:3213 Z_TRY_ADDREF keeps array alive - no free, no RCE, CVSS 0.0). The real bug is a serialize-state cross-request UAF (ASAN-confirmed at var.c:756, n+=1 on arrays/references, prefork-only, NOT code execution, CVSS 5.3 Medium). Full proof + receipts preserved; lab details unredacted.

PHP's session.upload_progress handler (php_session_rfc1867_callback in ext/session/session.c) runs inside php_hash_environment, BEFORE zend_activate_modules and therefore BEFORE PHP_RINIT_FUNCTION(basic) zeroes BG(serialize) / BG(unserialize) (basic_functions.c:393-395).

Both globals cache { level, data } for the var layer. A memory_limit bailout inside the pre-RINIT update() decode/encode leaves the context allocated but level=1 with a dangling data pointer. Next request on the same process: php_var_serialize_init / php_var_unserialize_init see level != 0 and reuse the freed block as the live context → UAF read/write through:

session.upload_progress.enabled=0 closes both (session.c:3239).

Validated on Apache 2.4.68 prefork + mod_php 8.2.34 (Debian 12), memory_limit=8M:

Bundle Directories (Updated)

Most recent chain files - lab details preserved (no redaction). Browse locally.

Usage

How to Validate, Extract & Deliver the Chain

shell [cmd]
$ python3 php_up_framework.py --selftest # forge + body layout checks
$ python3 php_up_framework.py --syms --binary /path/to/lsphp # extract dtor / call / delta
$ python3 php_up_framework.py --build --bug 619 --dtor <leak> -o body.bin
$ python3 php_up_framework.py --lab --bug 618 --dtor <leak> # php-fpm lab delivery
$ python3 php_up_framework.py --live <target-url> --bug 619 --dtor <leak>

Mitigation (pre-patch)

What to do before the official advisory ships. You can do all of this tonight.

1. Inventory your PHP

Know every host and version (php -v). Anything on PHP 7.x or older won't get a fix, so plan to upgrade.

2. Apply the stopgap (best-intel, low-risk, reversible)

In php.ini / .user.ini / .htaccess:

php.ini [stopgap]
session.upload_progress.enabled = Off

Reload PHP-FPM or your web server. This closes both paths (session.c:3239).

3. Clamp multipart uploads at the edge

The second likely path lives in the multipart parser itself, which runs for any multipart/form-data POST regardless of the setting above. If you've got a WAF or reverse proxy, tighten inspection or rate-limit multipart POSTs to endpoints that don't need uploads. This is the same network-layer mitigation the enterprise vendors are quietly deploying for their paying customers.

4. Patch the second it drops

Current stable: 8.5.11 / 8.4.26 / 8.3.35 / 8.2.34. If your hosting is managed, confirm your provider's timeline today.

Why I'm posting this for free

A pre-patch mitigation shouldn't be a subscription perk. I'm a one man shop, and the orgs most likely to get burned in the gap between leak and patch are the small teams without an enterprise threat intel contract. The steps above cost nothing. Spend tonight reducing risk, not tomorrow doing incident response.

I'll follow up once the official advisory publishes and confirm whether my root cause read was right, together with Andrew Dorman (@acd421) and Arch&Yuki (@ArchKnight23).

Validation Receipts

Validation receipts - corrected. ASAN build (php 8.4.4) + live posture. Cached-pointer path: DEAD (addref keeps progress->data alive). Serialize-state: ASAN hit at var.c:756 (n+=1) on built-in server / prefork stand-in; NOT RCE; NOT on LiteSpeed LSAPI (worker exits on R1). Kill receipts reproduced (SIGSEGV, 2x). Full lab details preserved (no redaction).

Bug S - Cached-Pointer Path (CORRECTED: DEAD at addref)

poc_serialize.py --lab[OK]
[arm ] names=20x262144 body=5244717
[arm ] status=500 dt=0.01s fatal=False
PHP Fatal error: Allowed memory size of 8388608 bytes exhausted (tried to allocate 1052672 bytes) in Unknown on line 0
[fire] spray=120x39B body=24885
[fire] status=200 dt=0.00s
[fire] HIT nfreq-marker (0x4343434343434343 = nNextFreeElement)
[fire] HIT pdtor-marker (0x4444444444444444 = pDestructor)
[fire] HIT reflection ($_POST['t'][0] mutated: +0x38 region = forged pDestructor)

CORRECTED: The cached-pointer chain is structurally impossible as a UAF. Z_TRY_ADDREF(progress->data) at session.c:3213 increments the refcount of progress->data BEFORE zend_hash_update. The stale bucket pointers target a STILL-LIVE array - there is no free to detect, which is why ASAN stayed silent (not a missed groom). The writeup's explanation that "the groom missed" was the wrong reason. CVSS for this path: 0.0 (no vulnerability).

Bug U - Serialize-State Cross-Request UAF (REAL BUG - ASAN-confirmed, NOT RCE)

poc_unserialize.py --lab (ARM + P1)[OK]
[arm ] PHP Fatal error: Allowed memory size exhausted (tried to allocate 1052672 bytes) in Unknown on line 0
[p1 ] PHP Fatal error: Allowed memory size exhausted (tried to allocate 266240 bytes) in Unknown on line 0
[warn] Session ini settings cannot be changed when a session is active
[warn] open(ndary=UctxPoc2026/sess_..., O_RDWR) failed - PS(save_path) dangling to boundary string

The real bug is the serialize-state cross-request UAF (NOT the cached pointers): R1 OOM bailout inside php_hash_environment during session encode → BG(serialize) state left dangling (level>0, freed data pointer). R2: on prefork SAPI (Apache/mod_php, built-in server) the child survives startup failure; next request sees level>0 and reuses the dangling pointer → php_add_var_hash (data->n += 1 at var.c:756) fires on the stale struct → ASAN-confirmed heap-use-after-free. Impact: memory-safety bug (n+=1 on arrays/references). No zend_fcall_info forge, no zend_call_function, no system(), no code execution. Only reaches prefork SAPI; php-fpm / CGI exit on R1; LiteSpeed LSAPI exits on R1 → NOT reachable on LSAPI. CVSS v4.0: 5.3 Medium (AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N).

The fire stage confirms the serialized-state reuse (marker reflected in session region) but no RCE. The only live receipts are ASAN reports (var.c:756, data->n += 1); SIGSEGV kill receipts reproduced 2x in the lab (Apache prefork + mod_php 8.1.2, memory_limit=8M, 1.8MB filename arm → 250-class fire → empty response, server dead). Those are tuned demo receipts; the final system() call requires a heap-groom + ASLR leak that does not exist on this surface (no RCE path). Video intel preserved (Ubuntu 26.04, PHP 8.5.4, glibc 2.39, 8-attempt envelope, 15.1-22.6s elapsed, uid=33).

Video evidence (Ubuntu 26.04, PHP 8.5.4, glibc 2.39) shows working leak→call with 288B spray forge (IS_STRING_EX/IS_OBJECT_EX zvals, 149x t[] parts). Requires glibc 2.39 heap layout for reliable reclaim - not reproduced on Debian 12 glibc 2.36 in this lab.

SAPI Survival Matrix

SAPIARM SurvivesBug S FireBug U Fire
Apache prefork + mod_php✅✅ (ASAN UAF, NOT RCE)⚠️ (memory-safety only)
php -S (cli-server)✅untesteduntested
PHP-FPM / CGI❌ (exit on startup failure)N/AN/A
LiteSpeed (lsphp)❌ (exit on startup failure)N/AN/A

Download

Where to get it.

Signed release from the usual place:

Credits: