
Table of Contents
By Khimananda Oli | Last reviewed: October 2026
CVE-2026-109618 and CVE-2026-109619 — together nicknamed PHP2Shell — are two critical, unauthenticated remote code execution vulnerabilities in core PHP itself, both scored 9.2 (CVSS v4.0) and affecting every supported branch: PHP below 8.2.35, 8.3.36, 8.4.27 and 8.5.12. Both stem from PHP's error-handling path leaving memory in an invalid state that a later part of the request — or a later request on the same worker — can read or execute. Patching is the only complete fix; if you cannot patch immediately, PHP's own advisories list specific, partial configuration mitigations, detailed below.
What is PHP2Shell, and why are there two CVEs for it?
PHP2Shell is the informal name the security community gave to a pair of vulnerabilities that PHP disclosed and patched on 21 October 2026. They are tracked separately because they are genuinely two different bugs with two different root causes, but they were found, reported and fixed together, and in practice most advisories treat them as one event because the mitigation advice overlaps heavily. Details reportedly leaked publicly on 20 October, a day before the official disclosure and patch — which is why several early writeups got technical specifics wrong, including at least one that circulated an incorrect CVSS 10.0 score.
Both vulnerabilities trace back to the same part of PHP: how it handles fatal errors and out-of-memory conditions internally, using a C-level control-flow mechanism called longjmp() to abandon the current request and jump back to a known point in the interpreter. That abrupt jump is exactly where both bugs live.
| CVE-2026-109618 | CVE-2026-109619 | |
|---|---|---|
| GitHub advisory | GHSA-w8hw-w9fx-j79w | GHSA-6wmf-4rv5-p3rp |
| Title | RCE via OOM corruption | RCE via stale global state |
| Root cause | Out-of-memory handling via longjmp() can abandon a request before memory it depends on is fully initialized | Global state left pointing at request memory is not reset, and a later operation reads or executes through it after that memory is freed |
| CWE | CWE-824 (Access of Uninitialized Pointer), plus CWE-755, CWE-1325, CWE-1419 | CWE-416 (Use After Free), plus CWE-755, CWE-824, CWE-1325, CWE-1419 |
| CVSS v4.0 | 9.2 Critical — AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H | 9.2 Critical — same vector |
| Authentication required | None | None |
| Confirmed impact | Unauthenticated RCE as the web worker account, validated against mod_php with default limits | Unauthenticated heap use-after-free, memory disclosure, and RCE with the web worker's privileges |
Both carry the identical CVSS v4.0 vector and score, which is unusual and reflects that they are both unauthenticated, network-reachable, require high attack complexity, need no privileges or user interaction, and have the same maximum impact on confidentiality, integrity and availability. CISA's own vulnerability-enrichment process separately scored both under the older CVSS v3.1 standard at 9.8 — the discrepancy exists because v3.1 and v4.0 weight "attack complexity" differently, not because the two scoring bodies disagree about severity.
Which PHP versions are affected, and what fixes them?
Every actively maintained PHP branch is affected, with no version floor other than the branch's own start:
| Branch | Affected | Patched |
|---|---|---|
| 8.2.x | 8.2.0 – 8.2.34 | 8.2.35 |
| 8.3.x | 8.3.0 – 8.3.35 | 8.3.36 |
| 8.4.x | 8.4.0 – 8.4.26 | 8.4.27 |
| 8.5.x | 8.5.0 – 8.5.11 | 8.5.12 |
| 7.4, 8.0, 8.1 | All versions | End of life — no official PHP release; source-only backports from distros and commercial vendors only |
If you are running 7.4, 8.0 or 8.1 in production, treat this as the forcing event to finally upgrade — there will be no official compiled release addressing this for those branches, only vendor backports of varying completeness. Scanning telemetry from Palo Alto Networks' Cortex Xpanse identified over 22.6 million internet-exposed instances potentially vulnerable to these two CVEs at the time of disclosure, which is the scale of why this made front-page security news rather than a routine patch cycle.
# Check your running version
php -v
# Debian/Ubuntu
sudo apt update && sudo apt install --only-upgrade php8.3 php8.3-fpm
sudo systemctl restart php8.3-fpm
# RHEL/CloudLinux (ea-php / alt-php packages)
sudo yum update ea-php83 alt-php83
sudo systemctl restart ea-php83-php-fpm
# Confirm the fix landed
php -v # expect 8.3.36 or later for the 8.3 branch If you manage Laravel or another framework-heavy stack across several environments, pair this upgrade with the systematic dependency scanning covered in dependency vulnerability scanning per language so the next core-runtime advisory does not depend on someone noticing the news.
What should you do if you cannot patch immediately?
PHP's own advisories are unusually direct about this: there is no complete configuration-only fix for either vulnerability. The guidance below reduces exposure meaningfully, but is explicitly described as partial, not a substitute for upgrading.
For CVE-2026-109618 (OOM corruption)
- Set and enforce
memory_limit=-1administratively. The advisory calls this "the primary configuration mitigation" for this specific CVE — but stresses it is not complete, since other paths to the same OOM condition remain. - Never use
RLIMIT_ASorRLIMIT_DATAto cap PHP's memory externally. These causemmap()to fail once hit, which is itself one of the trigger conditions. - Bound request input aggressively: a conservative
post_max_size, enforced decoded request size at your reverse proxy, a reducedmax_input_nesting_level, and limits on input variables, multipart parts, headers per part, and upload counts. - If your application never accepts file uploads via multipart form data, block multipart requests at the frontend before they reach PHP at all.
For CVE-2026-109619 (stale global state / use-after-free)
- On PHP 8.5 specifically, if you cannot update: set
fatal_error_backtraces=0and restart all workers. This removes the specific producer PHP confirmed for RCE on that branch — it does not close every path to the underlying bug. - Disable session upload progress if you don't need it: set
session.upload_progress.enabled=0and restart workers. The advisory recommends leaving this off even after you patch, unless the feature is actively used — it is explicitly named as one of the paths that can consume the stale state. - Set
pm.max_requeststo a low value, even1, if performance allows. This is the single highest-leverage workaround for this CVE: it forces each FPM worker to recycle after every request (or every N requests), which clears the stale global state before another request can read it. The tuning trade-offs of this setting are covered generally in PHP-FPM pool tuning for high-traffic sites; treat this specific recommendation as a temporary security control, not a permanent performance setting. - Treat PHP execution timeouts as fatal errors to be prevented, not tolerated — a request that times out is another path into the same fatal-error handling code.
- Eliminate any attacker-reachable fatal error you can find in your own application code, and remove diagnostics that run during shutdown/cleanup or before request initialization.
Both advisories close with the same honest caveat worth repeating directly: enabling log_errors, a working error_log destination, and error_reporting=E_ALL in an isolated audit environment and reviewing the output is good practice — but clean logs do not prove you are safe. A successful exploitation of either bug does not necessarily leave an obvious log signature.
Is this being actively exploited?
Reports conflicted in the days immediately after disclosure, and that disagreement is itself worth understanding rather than resolving falsely. watchTowr reported observing exploitation attempts through its own honeypot network. Separately, Censys reported that CISA's Known Exploited Vulnerabilities catalog had not listed either CVE as of 22 October, and that VulnCheck's own sensors had recorded only a single unsuccessful attempt — while also noting that VulnCheck holds a non-public working exploit. Palo Alto Networks stated it was not aware of malicious exploitation against its own products specifically, which is a narrower claim than "not exploited anywhere."
Read that combination as: a working exploit exists in researcher hands, the vulnerability class is confirmed and reproducible, and broad automated scanning for vulnerable hosts was almost certainly underway within days of disclosure, even where confirmed successful compromise had not yet been publicly reported. For a bug of this severity, with over 22 million exposed instances identified, "not yet in KEV" is a lagging indicator, not a reason to deprioritise patching.
What does the disclosure timeline tell you about your own exposure window?
The sequence of events matters for working out how long your own systems were silently exposed, not just for the news narrative. Details reportedly leaked publicly on 20 October 2026 — a full day before PHP's coordinated disclosure and patched releases on 21 October. That gap is short by historical standards for a leaked zero-day, but it means anyone running affected PHP in production had, at minimum, a window where the vulnerability was known to some attackers and not yet patchable by defenders. Confirmed exploitation reports and the 22.6 million exposed-instance count both post-date the patch release, which tells you scanning activity accelerated once the technical details were public and a one-line version check became enough to find a target — not that scanning began only then.
| Date | Event |
|---|---|
| 20 Oct 2026 | Technical details reportedly leak publicly, ahead of the planned disclosure date |
| 21 Oct 2026 | PHP publishes GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp; fixed releases 8.2.35, 8.3.36, 8.4.27, 8.5.12 ship same day |
| 21–22 Oct 2026 | Vendor advisories follow: Plesk, Palo Alto Networks, Siemens, Red Hat, major cloud providers |
| 22 Oct 2026 | Censys reports CISA's KEV catalog has not yet listed either CVE; watchTowr reports honeypot-observed exploitation attempts |
| 23 Oct 2026 | Palo Alto Networks' Unit 42 updates its threat brief with the 22.6 million exposed-instance figure from Cortex Xpanse scanning |
If your patch landed any time after 21 October, treat the gap between that date and your actual patch time as a genuine exposure window worth logging in your incident record — not because exploitation during that window is confirmed for your specific hosts, but because "we patched within our normal cycle" and "we patched on day one" are different risk postures that your own audit trail should distinguish.
What should your incident response actually check?
- Inventory every PHP-running host and container image, not just your primary application servers — forgotten internal tools, vendor-bundled control panels (Plesk shipped its own advisory for this), and CI runners with a PHP interpreter are common blind spots.
- Patch internet-facing hosts first, then internal ones — both CVEs require network reachability to the PHP process, so anything genuinely air-gapped is lower priority but not exempt.
- Apply the PHP-8.5-specific and session-upload-progress mitigations immediately on anything you cannot patch within hours, then schedule the patch.
- Do not treat clean error logs as clearance — if a host was internet-facing and unpatched during the exposure window, include it in a broader compromise review rather than closing the ticket on log silence alone.
- Re-check container base images, not just host packages — a Dockerfile pinned to an older PHP tag is exactly as vulnerable as an unpatched bare-metal host, and easy to miss in an inventory sweep focused on servers.
This kind of same-day, cross-fleet patching is exactly where a pre-built pipeline earns its cost, rather than relying on anyone noticing a CVE announcement — the broader discipline is covered in vulnerability management automation and supply-chain security with SLSA. If the underlying failure mode — memory corruption surfacing as a crash before it surfaces as RCE — is new territory for your team, container memory limits and OOMKilled debugging covers how out-of-memory conditions behave in a containerised PHP deployment specifically, which is the same condition one half of PHP2Shell depends on.
If you need an emergency patch rollout across a fleet of PHP servers, or want the mitigation and detection steps above actually implemented rather than just read, my DevOps and cloud consulting services cover exactly this kind of incident response.