php2shell (CVE-2026-109618/619) differential lab: ASAN builds of PHP 8.4.26 vs 8.4.27, one two-request trigger, automatic crash/no-crash verdict. Reproduces the fixed state-corruption bug — not RCE.
# php2shell-lab
**Two requests crash PHP 8.4.26 before a single line of your application runs. The exact same two requests do nothing to 8.4.27.**
A differential lab for the `php2shell` fixes (CVE-2026-109618 / CVE-2026-109619): both PHP versions built from source, the same trigger, an automatic crash / no-crash verdict — plus a hands-on review of every public "php2shell PoC" that was making the rounds.

[](https://github.com/allureluoli/php2shell-lab/actions/workflows/ab.yml)



**[中文说明 → README.zh-CN.md](README.zh-CN.md)**
<img src="assets/demo.svg" alt="quickstart output: the vulnerable build dies, the fixed build survives" width="900">
## The 20-second version
`session.upload_progress` is on by default, and PHP parses a multipart body **before RINIT** — inside `php_request_startup() → php_hash_environment()`. That path decodes and encodes session data. If the encode runs out of memory, PHP 8.4.26 bails out with the serialization context still "live" but pointing at freed memory. The **next request in the same process** reuses it, again before RINIT:
```
AddressSanitizer: SEGV on unknown address 0x138 (READ)
#0 tmp_var ext/standard/var_unserializer.c:168
#2 ps_srlzr_decode_php ext/session/session.c:1134
#4 php_session_initialize session.c:502
#5 php_session_rfc1867_cleanup session.c:3211
#6 php_session_rfc1867_callback session.c:3375
#7 rfc1867_post_handler main/rfc1867.c:1273
#12 php_hash_environment main/php_variables.c:788
#13 php_request_startup main/main.c:1873
```
8.4.27 (`506e87fa`