Every claim in our security writing is supposed to be checkable. When a critical flaw lands, the honest way to say this is real is to reproduce it ourselves, in a box that cannot touch anything else, and then show our work. This is how we did that for php2shell: the pair of critical PHP engine flaws, CVE-2026-109618 and CVE-2026-109619, that were already being exploited in the wild before they were disclosed. [Confirmed]
What follows is the methodology, not a how-to. How we built the lab, how we proved code execution without trusting the exploit’s own success message, what our negative controls do and do not mean, and how we keep the evidence honest. We hold the offensive detail back on purpose, and we say why at the end.
The lab
A proof is only trustworthy if it cannot reach anything real. Ours runs two containers on a Docker network with no route to the internet, and nothing about it touches a production system, a client or a third party.
How the lab is built
01Isolated by design
An attacker box and a PHP victim sit on a Docker network marked internal, with no egress, no published host port and image digests pinned. Evidence is mounted read-only, so a process that runs during the test cannot rewrite it.
02A deliberately legible target
php:8.4.26-apache, mod_php, a single prefork worker, withdisplay_errorson and session upload progress enabled. One worker keeps requests from scattering and makes the behaviour repeatable. It is a lab, not a model of every PHP server in production.03A public PoC, read before it ran
We did not write a new exploit. We took a publicly posted proof of concept, read its code first, pinned it to one target URL and two fixed commands, and disabled its target-list and built-in listener features. The goal was to observe a known chain safely, not to build a weapon.
Proving execution, not trusting a banner
An exploit that prints SUCCESS is not proof of anything. The public PoC we used prints a BLIND_OK message once it has sent its final stage, whether or not a command actually ran, and its --proof-file option is declared but never checked. [Confirmed] Trust that message and you report a result the lab never produced.
So we wrapped the chain in a small harness. Before each run it clears a shared marker file and records the target’s exact PHP version and configuration. It runs the chain. Then it refuses to call the run a success unless the marker holds exactly the output of id for the web user: uid=33(www-data). The proof is the effect, measured on its own, not the exploit’s opinion of itself.
Against the vulnerable target the chain did more than drop a file: it opened an interactive session back to the attacker box. Here is that session, with the lab’s network identifiers, ports and memory details removed. What stays is what proves the point: the web user, the hostname and the operating system.

That is remote code execution as www-data: not root, and no container escape, but enough to read the application code, configuration and secrets the web user can reach. [Our assessment]
What the negative controls mean, and what they don't
A result is only as useful as its controls. We re-ran the exact same chain, with the exact same harness, against three changed configurations:
| Configuration | Result of the chain |
|---|---|
| PHP 8.4.26, upload progress on, 8 MB memory limit (vulnerable) | Interactive shell as www-data; marker written |
| PHP 8.4.27 (the fixed release) | No marker; the chain gave up |
| PHP 8.4.26 with session upload progress off | No marker; the chain gave up |
PHP 8.4.26 with memory_limit=-1 | No marker; the chain gave up |
It is tempting to read the bottom three rows as a checklist. They are not. Each one means only this chain did not reproduce in this configuration, not that the host is safe. They hold for one public chain and one profile. An attacker can carry a different variant or adapt the primitives, and PHP is explicit that there are no complete mitigations: updating is the only safe choice. [Confirmed] Upload progress off and memory_limit=-1 each cut a single path; they are stopgaps, not fixes.
Evidence you can check
Every log and the terminal capture are hashed. A SHA256SUMS file lets anyone who receives the evidence confirm it is the same bytes we produced, and each run log carries its own UTC timestamp and the baseline configuration it ran against. We are careful about the claim: the artifacts are reproducible and hashed, but they are editable files, not a forensic chain of custody, and we say so. [Our assessment] We also publish nothing captured from memory during a run. Those bytes can hold credentials, so the public evidence is limited to lab addresses, configuration and non-sensitive output.
Root cause, at advisory depth
PHP reads multipart form uploads before your application code runs, which is why neither flaw needs a login or a vulnerable plugin to be reached. [Confirmed] From there, the two CVEs are two ways the engine can be left holding bad state:
- CVE-2026-109618, “RCE via OOM corruption.” If the engine runs out of memory, or hits a fatal error, mid-parse, it can jump out before cleanup finishes, leaving internal request structures half-built. Later cleanup can treat them as valid.
- CVE-2026-109619, “RCE via stale global state.” State that belongs to one request can survive in the worker’s globals after its memory is freed. A later request served by the same worker can consume that freed state before normal initialization runs.
The fixed release, 8.4.27 and its siblings, closes this at the lifecycle level: it defers the out-of-memory handling to a controlled point instead of jumping out of the allocator, resets superglobals and request state before the next request begins, and hardens the session and multipart code paths. That is the only complete fix. We confirmed the chain stops on 8.4.27 in our lab, which is corroboration, not a guarantee that every variant is dead. [Our assessment]
What this is already doing in the wild
[Confirmed] This is not theoretical. Amazon’s honeypots logged an exploitation attempt on 17 October 2026, four days before public disclosure, and Amazon describes php2shell as being broadly exploited, while noting it is unclear whether those attempts would have succeeded on real systems. Cloudflare reports attack traffic against its customers and attackers mutating their payloads to slip past rules. As of CISA’s 21 October catalogue the two PHP CVEs were not yet in the KEV list, and absence there is not absence of risk.
The full technical write-up
How we run red-team engagements
This is the discipline we bring to an engagement: reproduce the claim, prove the effect rather than the banner, control for what you are actually testing, and keep the evidence honest. If you want that applied to your own environment, that is what we do: a red-team engagement, an assumed-breach test that starts from a foothold, a secure code review of the application behind the server, or a compromise assessment to find out whether anyone is already inside. Patch php2shell first; then decide what you want tested.
9 sourcesphp.net+7+5ShowHide
- 01php.net
PHP, October 2026 security releases: fixed versions, CVSS, affected SAPIs and the statement that updating is the only complete fix.
- 02github.com
GitHub Security Advisory, GHSA-w8hw-w9fx-j79w: CVE-2026-109618, RCE via OOM corruption.
- 03github.com
GitHub Security Advisory, GHSA-6wmf-4rv5-p3rp: CVE-2026-109619, RCE via stale global state.
- 04calif.io
Ryan Austin, Calif, php2shell: naming, affected paths and the request lifecycle behind the chain.
- 05thephp.foundation
The PHP Foundation, Today’s PHP security release and how we’re strengthening PHP security: the disclosure timeline.
- 06aws.amazon.com
AWS Security, Amazon threat intelligence identifies php2shell exploitation prior to public disclosure in MadPot: the 17 October honeypot attempt and the “broadly exploited” wording with its caveat.
- 07blog.cloudflare.com
Cloudflare, PHP vulnerabilities and our WAF protection: attack traffic and payload mutation.
- 08tenable.com
Tenable, php2shell frequently asked questions: the caution that unverified PoCs can carry malware.
- 09cisa.gov
CISA, Known Exploited Vulnerabilities Catalog: KEV status check.




