Security
PHP2Shell: How Two Flaws in PHP Itself Turn a Web Request Into a Shell (CVE-2026-109618 & CVE-2026-109619)
October 25, 2026 · 9 min read
Not a plugin, not a framework, not a CMS — the language runtime itself. Two critical flaws in PHP core let an unauthenticated stranger run code on the server that answers a web request, and the patch only reaches the PHP you know you are running. A story about the thing underneath the thing you patched, with the fixed versions, the mitigations, and the controls it tests.
Most vulnerability stories are about a product: a firewall, a VPN, a management console. You know where it lives, because you bought it. This one is different. PHP2Shell is a pair of flaws in PHP itself — the runtime that sits underneath WordPress, Laravel, Magento, hosting panels, and a great many internal tools nobody has touched in years. When the bug is in the engine, the question is not “do we run that product?” It is “where, across everything we own and everything we depend on, is there any PHP at all?”
The setting: a runtime that answers the whole internet
PHP’s job, in most deployments, is to take an HTTP request from a stranger and run code in response. That is what it is for. So a flaw that can be reached by an ordinary-looking request is not an edge case — it is the front door. CISA’s alert says the two vulnerabilities affect PHP installations serving web requests, including Apache with mod_php, PHP-FPM, php-cgi, FrankenPHP, and LiteSpeed. The PHP project itself considers Apache mod_php the highest risk, because an attack there can succeed before the application’s own code runs — which means the code you wrote and reviewed never gets a chance to say no.
The two bugs, in plain terms
Both are rated CVSS v4.0 9.2 by the PHP project, and both let an unauthenticated attacker execute their own code on a server running PHP, as the web worker account. They are different mistakes with the same ending.
- CVE-2026-109618 — memory corruption under an out-of-memory condition. If PHP runs out of memory partway through setting up a request, it can leave half-built internal data behind for cleanup code to trust. An attacker who can push a worker into that state can turn the leftover mess into code execution.
- CVE-2026-109619 — a use-after-free caused by stale global state. PHP keeps internal state that outlives the request memory it points to, and the next request handled by the same worker can act on that leftover data. Akamai’s analysis ties it to the session upload-progress feature, which is on by default: any endpoint that accepts uploads is in scope, even one that ignores them.
HTTP request (no authentication)
|
| hits PHP core before / outside your application logic
v
PHP runtime mishandles memory it already freed (or half-built)
|
v
attacker-supplied code runs as the web worker accountWe are deliberately not describing how to trigger either bug. Public proof-of-concept code exists, and Qualys specifically advises against running it on production systems because it can tie up workers and write attacker-controlled data to disk. What matters for a defender is the shape: reachable without credentials, running as the account that serves your site.
The facts
| Field | Detail |
|---|---|
| CVEs | CVE-2026-109618 (out-of-memory corruption) and CVE-2026-109619 (use-after-free / stale global state) |
| Severity | CVSS v4.0 9.2 for each (PHP project rating). Unauthenticated remote code execution as the web worker account |
| Affected | PHP installations serving web requests: mod_php, PHP-FPM, php-cgi, FrankenPHP, LiteSpeed. Supported branches below the fixed builds; the older branches below too |
| Fixed in | PHP 8.5.12, 8.4.27, 8.3.36, 8.2.35 (released October 21, 2026) |
| No official fix | PHP 8.1, 8.0 and 7.4: no upstream release — use a distribution/LTS build or PHP’s limited source backports. PHP 7.3 and older (including PHP 5): affected, no fix — upgrade |
| Exploitation | Disputed — see “What is not settled yet” below |
What happened, and how fast
The PHP project pre-announced a critical security release on October 20 and shipped it on October 21. According to Akamai, the CVE identifiers leaked before the scheduled details were published. Hosting vendors such as Plesk published their own advisories, and Qualys reported that 199,000 installations were patched in the first 12 hours after disclosure. That is a fast response — and it makes the remaining installations stand out.
Qualys, analysing anonymised data from more than 10,000 customers, counted 167 million PHP package installations, of which 156 million have a known version. Of those, 73% sit on internet-facing assets. Only about 28% (44 million) run a supported branch where a fix exists; roughly 71% (110 million) run PHP 5.4 through 8.1. These are one vendor’s figures from its own customer base, not a census of the internet — but the proportion is the point: most PHP in the wild is on a branch that does not get an upstream fix.
What is not settled yet
Be careful with any headline that says this is “actively exploited” or “not exploited” — the sources disagree, and it matters.
- watchTowr reports exploitation in the wild since October 21, observed through its Attacker Eye honeypot network, and marks both CVEs as exploited. No threat actor has been publicly attributed.
- CISA’s alert (published October 21, revised October 23) says it has not observed successful exploitation in the wild.
- Neither CVE appears in the CISA Known Exploited Vulnerabilities catalog as of the catalog’s October 23 release.
The sensible reading is not to pick a side. Honeypot traffic proves attackers are trying; it does not prove they are succeeding against real targets. But a pre-authentication RCE with public proof-of-concept code is not a risk you wait on. Treat it as exploitable now, and re-check the KEV catalog — if either CVE is added, federal deadlines will follow quickly.
The fix, and what to do if you cannot patch yet
- Update to the fixed release for your branch (8.5.12, 8.4.27, 8.3.36 or 8.2.35) — and restart every PHP worker afterwards. A patched package on disk does not protect a worker that is still running the old code.
- On a distribution-packaged PHP, check your vendor’s advisory rather than the version number. Backported fixes often keep an older upstream version string, so a patched distribution package can still report a version that looks old — the vendor advisory, not the number, tells you whether it is fixed.
- On PHP 8.1, 8.0 or 7.4, use a distribution or LTS vendor build, apply PHP’s source backports, or upgrade. On PHP 7.3 and older there is no fix at all — upgrade to a supported branch, or take the system off the internet.
- If you cannot patch today, restrict internet access to that system. CISA’s guidance is explicit: take PHP-based systems offline if they cannot be updated immediately, and consider a web application firewall as interim protection, not as a fix.
- The PHP project’s interim hardening, as relayed by Qualys, includes setting session.upload_progress.enabled=0 in the main PHP configuration before request parsing (not via ini_set() or .user.ini), lowering post_max_size, and limiting request size at the web server or proxy — then restarting workers. PHP states that no configuration change fully mitigates the flaws, so treat these as buying time, not as closing the hole.
Finding the PHP you did not know you had
The hard part is rarely applying the patch. It is the inventory. Qualys’s guidance is blunt: look beyond the obvious web servers to parallel PHP branches on the same host, containers, hosting-panel packages, and PHP bundled inside appliances and other software. It also warns that php -v can report a different installation from the one actually serving web requests — the binary on your path is not necessarily the one answering the internet.
# Which PHP binaries exist, and which versions?
find / -type f \( -name "php" -o -name "php-fpm*" -o -name "php-cgi" \) 2>/dev/null
# What is the running web-facing PHP actually?
ps aux | grep -E "php-fpm|php-cgi|apache2|httpd|litespeed|frankenphp"
# Package-managed PHP (compare to your distro's advisory, not just the version string)
dpkg -l | grep -i php # Debian / Ubuntu
rpm -qa | grep -i php # RHEL / Alma / RockyFor hunting, CISA’s alert points to behaviour rather than a signature: PHP worker processes launching shells or downloading tools are the thing to look for, and CISA added SIGMA detection rules in its October 23 update. A web worker that spawns sh, bash, curl or wget is almost never legitimate. If a system was exposed and unpatched after October 21, assume it may have been touched and hunt, rather than just patching and moving on.
The part auditors test: this is a controls story
Strip away the memory-safety detail and PHP2Shell is a checklist of controls every serious framework already requires. An unpatched critical vulnerability, an asset you could not account for, an unsupported runtime still in production, and a web tier with no egress control are not new risks — they are the exact things a SOC 2 or ISO 27001 auditor tests. Here is how the flaw maps to the controls that contain it.
| Control | Framework | What this incident tests |
|---|---|---|
| Vulnerability & patch management | SOC 2 CC7.1 · ISO 27001 A.8.8 | A critical, pre-auth RCE needs a defined detect-and-patch SLA — and a restart, because a patched file on disk does not protect a running worker. |
| Asset inventory | SOC 2 CC6.1 · ISO 27001 A.5.9 | You cannot patch PHP you do not know about. Bundled, containerised and forgotten PHP is exactly where the exposure hides. |
| Unsupported software | SOC 2 CC7.1 · ISO 27001 A.8.8 | About 71% of PHP installs counted by Qualys are on end-of-life branches. A runtime with no upstream fix is a standing finding, not a one-off. |
| Network exposure & egress | SOC 2 CC6.6 · ISO 27001 A.8.20 / A.8.22 | Restricting access to systems that cannot be patched, and limiting what a web worker can reach outbound, is what turns a compromise into an incident instead of a breach. |
| Monitoring & detection | SOC 2 CC7.2 · ISO 27001 A.8.15 / A.8.16 | A web worker spawning a shell or fetching tools is the signal CISA calls out; logging and alerting are how you see it. |
The uncomfortable question: do you know where your PHP is?
The hardest part of PHP2Shell is not the upgrade on the server you already know about. It is the one you do not: the old marketing microsite, the vendor’s hosted portal, the appliance with a web admin page, the staging box nobody decommissioned. That is an attack-surface question, and it is answerable in part. Continuous attack-surface monitoring discovers what you expose to the internet — including web servers and the software they reveal — so a forgotten, unpatched host surfaces as a finding instead of a surprise. It cannot see PHP that does not advertise itself, and it is not a substitute for patching: remediation here comes from the PHP project’s and your vendors’ advisories. What it does is shrink the set of places you did not know to look.
CATAAM pairs that discovery with continuous control monitoring, so the fix does not end as “we patched it” in a chat thread: each remediation becomes dated, tested evidence against SOC 2, ISO 27001, and the other frameworks you carry. The teams that get through weeks like this one calmly are not the lucky ones — they are the ones who had an inventory before the advisory landed.
The same pattern played out in the N-able N-central master-key story: a flaw in something underneath, reachable from the internet, with a patch that only helps people who know they need it.
See what your organization exposes to the internet, before an attacker does.
Run a free attack-surface scan →Frequently asked questions
- What is PHP2Shell?
- PHP2Shell is the nickname for two critical vulnerabilities in PHP core, CVE-2026-109618 and CVE-2026-109619. Each is rated CVSS v4.0 9.2 and each lets an unauthenticated attacker execute their own code on a server running PHP, as the web worker account. The PHP project released fixes on October 21, 2026.
- Which PHP versions are fixed?
- PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 contain the fixes. PHP 8.1, 8.0 and 7.4 have no official upstream release — use a distribution or LTS vendor build, PHP’s limited source backports, or upgrade. PHP 7.3 and older, including PHP 5, are affected and have no fix, so they must be upgraded to a supported branch.
- Is PHP2Shell being exploited in the wild?
- Sources disagree. watchTowr reports exploitation since October 21, 2026, seen through its honeypot network. CISA’s alert (revised October 23) says it has not observed successful exploitation in the wild, and neither CVE was in the Known Exploited Vulnerabilities catalog as of its October 23 release. Treat it as exploitable now: it is pre-authentication, and public proof-of-concept code exists.
- Does updating the package fully protect me?
- Only once every PHP worker has restarted. A patched package on disk does not protect a worker still running the old code. Also check your distribution’s advisory rather than the version number: distributions often backport the fix while keeping an older upstream version string, and php -v may report a different installation from the one serving your web requests.
- Can I mitigate it with a configuration change?
- The PHP project states that no configuration change fully mitigates these vulnerabilities. Its interim hardening, such as disabling session.upload_progress in the main PHP configuration, lowering post_max_size and limiting request size at the web server, and then restarting workers, buys time but is not a substitute for patching. If you cannot patch, restrict internet access to the system.
- I do not run PHP myself. Am I affected?
- Possibly, through software you depend on. PHP is bundled inside hosting panels, appliances, CMS platforms and vendor-hosted portals. Ask vendors in writing whether any of their internet-facing components run PHP, which branch, and whether it has the October 21 fixes. Then check your own estate, including containers and forgotten staging hosts.