Follow the request through the PHP worker. Then check your running build, verify temporary controls, and understand what public lab tools actually measure.
Anatomy of an exploit.
Two paths through the request lifecycle. An attack does not have to combine both.
HTTP → PHP → WORKER STATESimplified lifecycle · based on upstream advisories
A request reaches an unpatched PHP worker.Runtime and application conditions determine the path.
CVE-2026-109618
An interrupted operation.
Cleanup encounters incomplete request state.
01
REQUEST / INPUT
PHP allocates request memory.
Input processing creates structures that can become reachable before initialization finishes.
02
INTERRUPTION / OOM
An allocation fails.
An out-of-memory exit interrupts the operation and leaves incomplete state.
03
SAME REQUEST / CLEANUP
Shutdown uses incomplete state.
Cleanup accesses it. A crafted memory layout can turn corruption into code execution.
Runtime matters. Confirmed before application code on mod_php. FPM exits on startup failure; later application-driven OOM remains susceptible, but this advisory demonstrates no complete FPM OOM exploit.
The worker retains request-owned data. An interruption skips reset, or late cleanup repopulates the reference.
02
REQUEST A / RELEASE
The request memory is freed.
Request memory is released while the worker keeps its reference.
03
REQUEST B / SAME WORKER
An early consumer uses it.
Another request reaches that worker. An INI diagnostic or session upload progress accesses stale memory before normal initialization.
Runtime matters. Confirmed: fatal-backtrace RCE on mod_php; session-lifecycle RCE on mod_php and FPM. FPM requires a suitable application operation after successful startup.
A successful chain can disclose memory or execute code with the web worker’s privileges. A crash alone is not proof of RCE.
What to connect in monitoring.
Observation leads along the request and worker lifecycle
Layer
Look for
Interpretation
Request
Multipart anomalies; repeated requests
Entry-point leads, not exploit proof
Worker
Memory errors; fatal errors; worker exits
Correlate by time and worker
Host
Unexpected child processes or outbound traffic
Investigate; quiet logs do not clear exposure
Evidence has limits.
Confirmed cases are attributed to PHP’s maintainers, not reproduced here. Lab behavior does not establish real-world exploitation. Read the lab limitations →
The repositories below were inspected as source. No exploit was executed for this site. Their findings and scripts vary in scope, and some explore related session or deserialization behavior rather than reproduce every path in the official advisories.
Keep reproduction in an isolated lab
Use only systems you own or are authorized to test. Bind lab services to loopback, avoid public FastCGI exposure, and inspect setup scripts before running them. Use disposable instances without production secrets.
There is no universal non-exploit HTTP probe that proves either PHP2Shell CVE is present or fixed. The strongest routine check combines your live web runtime, the installed package or image, and an advisory confirming both fixes.
1. Read your private runtime diagnostic
Use the access-restricted diagnostic from the Patch guide, or your existing authenticated inventory endpoint. Replace the URL and use its normal authentication. An arbitrary application URL will not return this information.
Compare the returned web-SAPI version with the first fixed releases. For vendor backports, check the exact package build and advisory. Verify every replica. The upload-progress value describes one feature; an Off value is not a patched-state verdict. Remove the temporary endpoint afterward.
2. Check a blanket multipart block
Use a disposable endpoint through the actual edge or web server you configured. This sends a normal form field, without a PHP upload-progress trigger or exploit payload. The endpoint may still process form submissions.
Evidence that both fixes are installed for that runtime
Coverage of other replicas or absence of earlier compromise
403 + matching rule log
The selected control rejected that request
PHP patch status or coverage of other paths
2xx response
The request was accepted
Vulnerability or successful exploitation
5xx, timeout, or crash
A failure worth investigating
A CVE-specific result or successful RCE
Upload-progress metadata
The feature ran in that lab configuration
Memory corruption or either CVE being exploitable
HTTP banners can be hidden, rewritten, or carry an older version with backported fixes. A missing version header, a failed PoC, or a clean log search cannot clear a deployment.
The linked article suggests useful practices: pin a reference build, observe request/session behavior, and compare a vulnerable build with a verified fixed one. The reviewed repository provides a research scaffold; it does not demonstrate a reliable end-to-end RCE chain.
Isolated, disposable lab only
The top-level Compose file publishes ports on all host interfaces by default. Before starting it, change each published mapping to an explicit loopback binding: 127.0.0.1:8898:80, 127.0.0.1:8899:8899, 127.0.0.1:8900:8899, and 127.0.0.1:8901:8899. Keep production data and credentials out of the lab.
shell / retrieve the reviewed source and inspect the configuration
git clone https://github.com/slabbdev/php2shell-cve-2026-109618-109619.git
cd php2shell-cve-2026-109618-109619
git checkout --detach 9d70d5c825e56ef413d6e7e3bae9a3d76ebc8d7c
# Read source and correct port bindings before startup.
docker compose config
python3 harness/race.py --help
After reviewing the source and applying the loopback bindings, start only the FPM/nginx lab. The ping endpoint starts a session; its response checks availability, not vulnerability.
shell / start the isolated lab and check availability
The following source-verified flags disable concurrent disturbance modes and send one upload with 1 KiB of file content plus multipart overhead. It still writes upload/session state. Use only the isolated lab.
Read the output correctly: the harness counts connectivity failures, accepts any HTTP status in its health probes, and discards upload outcomes. failures=0 does not prove a successful upload, a safe runtime, or either CVE. There is no --check or --dry-run mode.
Its INI settings change progress cleanup and update frequency, so persistent metadata is not evidence of default production behavior. The separate WordPress impact payload assumes code execution; it is not a chain produced by this harness. Keep patched/unpatched comparison results tied to exact builds and actual memory-error evidence.
Community PoC source and mitigation examples for PHP, Apache, Cloudflare, FrankenPHP and lighttpd. The reviewed snapshot contains poc_109618.py despite the README's older coming-soon notice.
Source inspected and Python syntax checked; exploit not executed. The script depends on build-specific addresses. Its presence does not establish reliable exploitation across PHP deployments.
Session-file injection and serializer-mismatch verification scripts, a deserialization UAF reproducer, and research notes. The described RCE chains require additional conditions such as application LFI, unsafe deserialization or a usable gadget.
Source inspected; scripts not executed. The lab generator uses a floating PHP image, publishes HTTP and FastCGI on all interfaces, and enables privileged mode with seccomp disabled. Review and isolate it before use; the supplied setup is not a safe localhost-only recipe.
Research bundle with claimed exploit implementations, a framework and validation notes. The repository credits J4ck3LSyN, Andrew Dorman and Arch&Yuki; reproduction claims remain attributed to its authors.
Source inspected; nothing executed. All four Python files in this reviewed snapshot fail syntax parsing at line 1 because uncommented prose precedes the shebang. The README also refers to directories absent from the snapshot. This is not a verified runnable package.
Upload/session research lab with pinned PHP images, nginx/FPM targets, a WordPress example and an AddressSanitizer build scaffold. Useful for controlled observation and build comparisons.
Source reviewed, not executed. The harness does not return a reliable vulnerability verdict; normal progress metadata is not proof of either CVE. Top-level port bindings require loopback correction. The separate impact payload assumes code execution rather than demonstrating how to obtain it.
Look for the configured denial and corresponding logs. A 403 is evidence of that request being rejected; it is not evidence that PHP is patched. See the compensating controls for matching configuration.
Signals to investigate
New or unusual multipart traffic, especially alongside memory-limit errors.
Repeated HTTP 500 responses, worker crashes, or unexpected process restarts.
Malformed or unusually large PHPSESSID response cookies.
Unexpected shell or transfer-tool processes started by PHP workers, and unfamiliar files in web roots or temporary directories.
Correlate these with your baseline and preserve relevant logs. None is conclusive by itself; absence of child processes does not rule out memory disclosure or exploitation.