What PHP2Shell is
"PHP2Shell" is the name that stuck to a pair of vulnerabilities in PHP core, disclosed on 21 October 2026 and tracked as CVE-2026-109618 and CVE-2026-109619. Both are rated critical (CVSS 9.2), both are unauthenticated, and both lead to remote code execution — an attacker who can send an HTTP request to a vulnerable site can, with no login and no user interaction, run their own code on your server. That is the worst class of web vulnerability there is, which is why it earned a nickname.
The flaw is in PHP itself, not in WordPress, Laravel, a theme or a plugin. Anything that runs PHP and accepts a form submission is in scope. Affected versions run from PHP 5.4 all the way through 8.5.11, which is to say: almost every PHP deployment on the internet that has not been patched since the disclosure. The fixed releases are 8.2.35, 8.3.36, 8.4.27 and 8.5.12 — if you are on an older 5.x, 7.x or early 8.x line with no backport, you are exposed until you upgrade.
How the exploit works
The vulnerable code is PHP's built-in handler for multipart/form-data — the format every browser uses to submit a form with a file upload, defined by RFC 1867. The same parser also handles ordinary URL-encoded form bodies.
CVE-2026-109618 works like this: the attacker sends a request whose body is deliberately crafted to make the form parser allocate more memory than the process is allowed, so the allocation fails partway through parsing. PHP then tries to clean up the request it was building — but the request is only half-initialised, and the cleanup frees and touches memory that was never fully set up. That corruption is the foothold. With the body shaped carefully enough, the attacker steers the corrupted memory into executing code of their choosing.
CVE-2026-109619 is the companion flaw: a use-after-free in the session and upload-progress machinery, where state left over from one request is reused by a later request on the same worker process. A long-lived PHP-FPM worker handles request after request; if one of them can leave a dangling reference behind, the next one can trip over it.
The detail that makes this dangerous in practice is the one that defeats the obvious defence. The malicious body stays under PHP's normal post_max_size limit — the default 8 MiB. The attack does not work by sending a giant request; it works by sending a structurally extreme one. So the first instinct — "just cap how big a POST can be" — does nothing, because the exploit was already living inside that cap.
Why this is hard for a normal WAF
Most web application firewall rules look for a string: a SQL keyword, a <script> tag, a path like /etc/passwd. PHP2Shell has no such string. The exploit is a shape, and it comes in two forms, either or both of which can appear in one request:
- An empty-filename part flood. A legitimate multipart form has a handful of parts. The exploit sends hundreds of parts, each one declaring
filename=""— an empty filename. Each such part forces the parser to set up and tear down an upload slot, and that churn is what drives the memory exhaustion. - Pathologically deep field nesting. PHP lets form fields describe arrays by name —
user[address][city]. The exploit abuses this with names nested absurdly deep —name="f[a][b][c][d][e]..."repeated far past anything a real form uses — forcing the parser to build a deeply nested structure.
Neither of these is a payload you can write a signature for. The part count and nesting depth vary from one attack to the next, and there is no magic byte sequence to pin a regex to. This is exactly why AWS's own guidance on the vulnerability is explicit that defenders should not rely on a per-CVE signature — a single-string rule is trivially evaded by changing the padding. The defence has to count and measure the structure of the request, not scan its bytes.
How to protect a PHP site
The order here matters, because only the first item actually removes the vulnerability.
1. Patch PHP. This is the only complete fix. Upgrade to 8.2.35, 8.3.36, 8.4.27 or 8.5.12 (or your distribution's backported equivalent). Everything else on this list buys you time; only the patch closes the hole.
2. As a stopgap, tighten the form parser. In php.ini, lower post_max_size toward what your forms actually need, reduce max_input_nesting_level (the default 64 is far deeper than any real form), cap max_input_vars, and disable session.upload_progress if you do not use it — that is the surface for CVE-2026-109619. These do not fix the bug, but they shrink the room the exploit has to work in.
3. Enforce structural limits at the edge. In front of the origin, reject requests that are structurally abnormal: too many multipart parts, field names nested past a sane depth, an unreasonable input count, or a decoded size that balloons past the raw one. Crucially this has to work on chunked / length-less requests too, because an attacker who omits Content-Length sidesteps any check that only reads the declared size.
4. Block multipart where you never accept uploads. Most endpoints — your login form, your API, your search box — have no reason to accept multipart/form-data at all. Refusing it there removes the attack surface entirely for those paths.
For the difference between this kind of request-shaping defence and volumetric mitigation, see WAF vs DDoS protection. The same edge that counts form structure is the one that enforces rate limits — and for a PHP CMS specifically, the endpoint-hardening in the WordPress protection guide covers the same ground.
How Itnetic protects its customers
Itnetic's edge WAF ships a structural PHP2Shell filter that runs on every POP, as part of the WAF that is already in front of every protected site. It inspects the shape of each request before that request ever reaches your origin: it detects the empty-filename part floods and the deep field-name nesting that define the exploit, and it does so by measuring the allocation shape — the counts and the depth — rather than matching a single signature. Because it keys on the structure and not a fixed byte pattern, it holds up against payload variants that would walk straight past a string-matching rule.
It is deliberately a challenge, not a hard block. A real visitor who happens to submit a large or unusual form is never cut off — at most their browser solves a quick, invisible proof-of-work before the request continues. That design choice is the whole point: the filter can be aggressive about shape without taking down a legitimate form or upload, because the cost of being wrong about a real visitor is a fraction of a second of CPU, not a broken page.
The honest framing is defence-in-depth. The Itnetic filter stops the exploit at the edge and gives you breathing room — it shields the origin while your own PHP patching is scheduled and rolled out — but it is not a reason to skip the patch. Patch PHP; let the edge cover the window in between. If you are not behind Itnetic yet, DDoS protection and the full WAF go live with two DNS records on a free plan, and the structural filter is on from the first request.