PHP2Shell: CVE-2026-109618 and CVE-2026-109619 Explained and Mitigated (2026)

Khimananda Oli 12 min read Database, Kubernetes and Containers
PHP2Shell: CVE-2026-109618 and CVE-2026-109619 Explained and Mitigated (2026)

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-109618CVE-2026-109619
GitHub advisoryGHSA-w8hw-w9fx-j79wGHSA-6wmf-4rv5-p3rp
TitleRCE via OOM corruptionRCE via stale global state
Root causeOut-of-memory handling via longjmp() can abandon a request before memory it depends on is fully initializedGlobal state left pointing at request memory is not reset, and a later operation reads or executes through it after that memory is freed
CWECWE-824 (Access of Uninitialized Pointer), plus CWE-755, CWE-1325, CWE-1419CWE-416 (Use After Free), plus CWE-755, CWE-824, CWE-1325, CWE-1419
CVSS v4.09.2 Critical — AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H9.2 Critical — same vector
Authentication requiredNoneNone
Confirmed impactUnauthenticated RCE as the web worker account, validated against mod_php with default limitsUnauthenticated 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.

One error path, two different bugsBoth trigger through PHP's longjmp()-based fatal error / OOM handlingFatal error / out-of-memorylongjmp() abandons the request mid-flightCVE-2026-109618GHSA-w8hw-w9fx-j79wThe jump happens before requestmemory finishes initializingShutdown reads uninitializedmemory as if it were validTrigger: multiple OOM strategies,confirmed against mod_php defaultsCVE-2026-109619GHSA-6wmf-4rv5-p3rpThe jump skips resetting globalstate tied to this requestA later request reads orexecutes through freed memoryTrigger: fatal errors, some INIdiagnostics, session upload progressBoth: no authentication, no user interaction, CVSS v4.0 9.2Fixed in 8.2.35, 8.3.36, 8.4.27, 8.5.12 — released 21 October 2026
PHP2Shell is two separate bugs sharing one trigger: PHP's longjmp()-based fatal error and out-of-memory handling, patched together on 21 October 2026.

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:

BranchAffectedPatched
8.2.x8.2.0 – 8.2.348.2.35
8.3.x8.3.0 – 8.3.358.3.36
8.4.x8.4.0 – 8.4.268.4.27
8.5.x8.5.0 – 8.5.118.5.12
7.4, 8.0, 8.1All versionsEnd 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=-1 administratively. 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_AS or RLIMIT_DATA to cap PHP's memory externally. These cause mmap() 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 reduced max_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=0 and 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=0 and 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_requests to a low value, even 1, 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.

Patch first. These buy time, not safety.PHP's own advisory: no configuration change is a complete fix1 · Patch to 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12The only complete fix for both CVEs — do this first, do this today2 · pm.max_requests as low as 1, restart workersHighest-leverage temporary control for CVE-2026-109619 specifically3 · session.upload_progress.enabled=0 + memory_limit=-1One targeted control per CVE, explicitly named in each advisory4 · Block multipart at the frontend, bound all input limitsReduces attack surface; does not close either root causeDo not stop hereClean logs after enabling full error_reporting do not prove you were not exploited —rows 2 through 4 are a bridge to patching, not an alternative to it
A mitigation priority ladder for PHP2Shell: every configuration step below the patch is explicitly partial, per PHP's own advisories.

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.

The exposure window, day by dayA leak ahead of disclosure means scanning activity likely started before most defenders could patch20 OctDetails leakahead of schedule21 OctPHP discloses +patches ship21–22 OctVendor advisoriesfollow22 OctFirst exploitationreports, KEV silent23 Oct22.6M exposedhosts reportedYour real exposure windowstarts at the leak on 20 Oct, not at your own patch date —log the gap between 21 Oct and your actual patch time as partof your incident record, not just the CVE numbers you fixed
The PHP2Shell disclosure timeline: a pre-disclosure leak means the real exposure window for defenders started before most teams could patch.

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.

DateEvent
20 Oct 2026Technical details reportedly leak publicly, ahead of the planned disclosure date
21 Oct 2026PHP 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 2026Vendor advisories follow: Plesk, Palo Alto Networks, Siemens, Red Hat, major cloud providers
22 Oct 2026Censys reports CISA's KEV catalog has not yet listed either CVE; watchTowr reports honeypot-observed exploitation attempts
23 Oct 2026Palo 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?

  1. 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.
  2. 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.
  3. Apply the PHP-8.5-specific and session-upload-progress mitigations immediately on anything you cannot patch within hours, then schedule the patch.
  4. 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.
  5. 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.

Frequently Asked Questions

The informal name for CVE-2026-109618 and CVE-2026-109619, two critical unauthenticated remote code execution vulnerabilities in core PHP, disclosed and patched together on 21 October 2026. They affect every supported PHP branch: 8.2 through 8.5.

CVE-2026-109618 occurs when out-of-memory handling abandons a request before its memory is fully initialized, so shutdown reads uninitialized memory. CVE-2026-109619 occurs when global state pointing at request memory is not reset, so a later operation reads or executes through memory that has already been freed — a use-after-free.

PHP 8.2.0 through 8.2.34, 8.3.0 through 8.3.35, 8.4.0 through 8.4.26, and 8.5.0 through 8.5.11. PHP 7.4, 8.0 and 8.1 are also affected but are end of life, so PHP has released no official fix for them — only source-only backports from distributions or vendors.

8.2.35, 8.3.36, 8.4.27 and 8.5.12, all released on 21 October 2026. Upgrading to the fixed version for your branch is the only complete remediation for either vulnerability.

No. Both CVEs are unauthenticated and require no user interaction, which is why both are rated 9.2 Critical under CVSS v4.0 and why PHP and multiple vendors urged immediate patching rather than a scheduled maintenance-window fix.

No. PHP's own advisories state there is no complete configuration-only mitigation for either CVE. The workarounds listed — disabling session upload progress, setting pm.max_requests low, bounding memory and input limits — reduce exposure but are explicitly described as partial.

Setting pm.max_requests as low as 1 and restarting PHP-FPM workers. Recycling workers after every request clears the stale global state the vulnerability depends on before a later request can read through it, though this comes at a real performance cost.

Yes if you don't actively use it. PHP's advisory names session upload progress handling as one of the paths that can consume the stale state behind CVE-2026-109619, and recommends setting session.upload_progress.enabled=0 and keeping it off even after patching unless the feature is required.

Reports conflict. watchTowr reported observing exploitation attempts via its honeypot network, while Censys noted CISA's KEV catalog had not listed either CVE as of 22 October and that confirmed exploitation sightings were limited. A working exploit is known to exist in researcher hands regardless of public exploitation volume.

Palo Alto Networks' Cortex Xpanse scanning identified over 22.6 million internet-exposed instances potentially vulnerable to the two CVEs at the time of disclosure, based on their own telemetry.

Yes. Reports indicate details circulated publicly on 20 October 2026, a day before PHP's official disclosure and patched releases on 21 October. Some of the early leaked write-ups contained inaccuracies, including an incorrect CVSS 10.0 score for the vulnerabilities.

It is described as the primary configuration mitigation for that specific CVE, but PHP's advisory is explicit that it does not fully close the vulnerability, since other paths to the same out-of-memory condition remain possible.

The vulnerabilities are in core PHP itself. Some vendors, including Palo Alto Networks and Siemens, published their own advisories assessing which of their products bundle an affected PHP version — check your specific vendor's advisory rather than assuming a product is affected or unaffected.

Yes. A container image built from an affected PHP base tag is exactly as vulnerable as an unpatched host, and is commonly missed when an incident response inventory focuses only on running servers rather than image build pipelines.

Immediately, on internet-facing hosts first. Both CVEs are unauthenticated, require no user interaction, score 9.2 Critical, and were affecting over 22 million exposed instances at disclosure — this is not a vulnerability to defer to a routine patch cycle.