This will be a living blog post. Changes and new information will be added as more updates become available.
This week, PHP disclosed two critical remote code execution flaws in PHP, CVE-2026-109618 and CVE-2026-109619, better known as php2shell. Every PHP build below 8.2.35, 8.3.36, 8.4.27, and 8.5.12 are affected, no configuration change fully address the vulnerabilities, and there is no (publicly available) way to safely prove exploitability from the outside.
With all of this in mind, fingerprinting each PHP version is our most reliable signal right now. Instead of proving exposure with an exploit, we instead need to know where PHP lives before the advisory drops. Our Attack Surface Management (ASM) platform already did this for us, and we have detection running across our customer base within an hour of PHP's advisory.
Key Takeaways
- CVE-2026-109618 and CVE-2026-109619 are unauthenticated remote code execution flaws in PHP core, rated 9.2 (critical) under CVSS 4.0 and fixed in PHP
8.2.35,8.3.36,8.4.27, and8.5.12. PHP publishes no fix for8.1and older. - PHP states there is no complete configuration mitigation for php2shell. Disabling
session.upload_progressblocks one demonstrated path, and updating PHP is the only complete fix. - No safe remote exploitability check exists for php2shell because triggering either flaw results in corrupting PHP worker memory on the server. Comparing the advertised PHP version against the fixed release is the safest external detection method.
- PHP version banners can be filtered behind CDNs, managed hosting, and bot protection, so a historical ASM inventory is more likely to catch hosts a live scan might miss.
- Sprocket's ASM already tagged which assets run PHP and which version, which turned a fleet-wide exposure check into a few filter against existing data.
What Are CVE-2026-109618 and CVE-2026-109619?
They are two separate memory-safety flaws in PHP core, and both end in remote code execution with the web worker's privilege.
CVE-2026-109618 is an out-of-memory (OOM) handling flaw. PHP uses longjmp() to abort a request on OOM. If an allocation fails while request memory is only partly initialized, the request shutdown procedure later reads that invalid memory. PHP's advisory describes several multipart parsing problems that push a request into OOM while it stays inside its apparent PHP limits.
CVE-2026-109619 is a use-after-free in worker-global state. Error, session, object, and extension states that point to one request's memory can survive into the next request and get consumed before initialization. Session upload progress is one demonstrated path, which is enabled by default, and no session_start() call is required.
PHP validated full RCE over HTTP against Apache mod_php with default input and memory limits, and validated the session lifecycle path against PHP-FPM. Both CVEs are rated high attack complexity under CVSS 4.0, but neither requires authentication or user interaction. Full details are in PHP's advisories, GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp.
Which PHP Versions Are Affected by php2shell?
Branch | Fixed in | Status |
|---|---|---|
|
| Patch available |
|
| Patch available |
|
| Patch available |
|
| Patch available |
| None | End of life, no fix published |
However, distribution packages make things more complicated. Since Ubuntu and other distributions backport fixes without changing the upstream version, a patched host may still advertise an older version number. To eliminate false positives, check the package's version against your distribution's advisory.
Why Version Detection Is the Safest Means for Detecting php2shell
Version comparison is the right detection method here because PHP's own advisory rules out the alternatives. It states there is "no complete generic configuration mitigation," and its detection guidance is a local log and configuration audit, not a remote check. Proving exploitability from the outside means deliberately corrupting worker memory on a production server. We don't do that to customer systems.
Unofficial exploit code circulated before the advisory went live. We analyzed it, iterated upon it, and built working POC's we found to work, but were unstable and would crash the production client assets by the class of the vulnerability itself. We don't run unofficial exploit code and we don't crash client production assets.
The manual check is one line:
curl -sI https://example.com/ | grep -iE '^(server|x-powered-by):'A PHP/8.3.33 banner is below the 8.3.36 fix, so the host is affected. However, if a CDN, managed hosting provider, or bot-protection layer strips the header and returns nothing. A missing banner means an unknown version, which is why relying on live scans alone isn't enough.
How Sprocket Mapped php2shell Exposure in Under an Hour
For every in-scope asset, our ASM tracks whether PHP is confirmed (a live X-Powered-By header, a PHPSESSID cookie, or CMS markers such as wp-content/), the PHP version, the detected technology stack, and which customer owns the asset. Finding exposure was a filter on that data: version below the branch fix, or a branch at end of life.
That filter returned a lot of assets with a confirmed PHP version. The long tail is long. The oldest build still serving traffic was PHP 5.2.17, from a branch that stopped receiving updates in 2011.
We then built a Nuclei template that reads the PHP version from response headers and compares it to the fixed release. It uses separate matchers for unpatched supported branches and for end-of-life branches, and it sends no payload. We tested it against a local environment covering the last vulnerable and first fixed release on every branch, plus end-of-life, missing-banner, and distribution-suffixed cases.
The stored data paid off the same day. One host that advertised PHP 8.3.33 in the morning was serving a bot-protection challenge page by the afternoon, with no version header at all. A live-only scan went quiet on that host. The ASM record still had the version.
What Should You Do About php2shell Now?
- Upgrade PHP to
8.2.35,8.3.36,8.4.27,8.5.12, or later. PHP calls this the only complete mitigation. - Migrate anything on PHP
8.1or older to a supported branch. There is no patch coming. - If you can't upgrade today, set
memory_limit=-1andsession.upload_progress.enabled=0administratively, setfatal_error_backtraces=0on PHP8.5, and restart every worker. These are partial controls, not fixes. - On distribution packages, apply the vendor package update and confirm the installed package version.
Conclusion
Rapid CVE response is a data problem before it's a scanning problem. When the vulnerable condition is "runs PHP below version X," the team that already knows where PHP runs gets to the answer first. A point-in-time pentest from last spring won't have a current inventory, and a discovery scan started after the advisory is already behind.
That's the case for continuous testing: the inventory, the tagging, and the people who know how to use them are already in place when the next advisory lands. If you want to know where your exposure sits before the next one, take a look at Sprocket's Continuous Penetration Testing.