Back to Blog

PHP2Shell Explained: The Bug in PHP Itself That Puts Millions of Websites at Risk — CVE-2026-109618 and CVE-2026-109619

This time the vulnerable code isn't a plugin, a theme or a framework — it's the PHP runtime underneath all of them. Two memory-safety flaws let an unauthenticated attacker turn a crafted web request into code execution, on default settings, across nearly every PHP version released since 2012.

Vulnerability Details
CVE IDs
CVE-2026-109618
CVE-2026-109619
CVSS v4.0
9.2 / 10 — Critical (both)
Product
PHP 5.4 – 8.5 (runtime)
Impact
Remote Code Execution
Authentication
None Required
Fixed In
8.5.12 · 8.4.27
8.3.36 · 8.2.35

PHP powers a huge share of the web — WordPress, Drupal, Joomla, Magento, Laravel and Symfony apps, phpMyAdmin, Nextcloud, billing portals and countless custom sites. Most PHP security news is about a bug in one of those applications. PHP2Shell is different: the flaws are in PHP's own request-handling code, so they can be reached before a single line of your application runs.

On October 21, 2026, the PHP project shipped emergency releases 8.5.12, 8.4.27, 8.3.36 and 8.2.35 to fix two vulnerabilities, CVE-2026-109618 and CVE-2026-109619. The research team at Calif, working with OpenAI and Wiz, dubbed the chain "php2shell" and confirmed pre-authentication remote code execution against default installs of several of the world's most popular PHP applications.

What Are the Vulnerabilities?

CVE-2026-109618 — Memory Corruption During Out-of-Memory Handling

From PHP's advisory (GHSA-w8hw-w9fx-j79w): "out-of-memory handling can interrupt PHP while internal request data is only partially initialized. Request cleanup may then treat the invalid data as valid." In other words, if an attacker can make PHP run out of memory at exactly the wrong moment while it is still building the request, the clean-up code later trusts half-built data structures — a classic path to memory corruption.

CVSS v4.0: 9.2 — CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N

CVE-2026-109619 — Use-After-Free via Stale Global State

From PHP's advisory (GHSA-6wmf-4rv5-p3rp): "request-owned internal state can survive after its backing memory has been freed. A later request handled by the same worker may use that stale state before normal initialization resets it." Because PHP workers are reused across many requests, an attacker can leave a "dangling" pointer behind with one request and trigger its use with the next. PHP also lists memory disclosure as a confirmed impact — which can leak secrets such as credentials and keys.

CVSS v4.0: 9.2 — CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N

Why "AC:H" doesn't mean "safe". The CVSS vector marks attack complexity as high because exploitation depends on memory layout and server setup. But the researchers achieved RCE on default configurations, and no login, user click or special feature is required. Treat this as a patch-now issue.

How the Attack Works (High Level)

Calif's technical write-up explains the chain in detail. We summarise the concepts here — not the exploit — so defenders understand what they are protecting against.

The Attack Chain, Step by Step
  • 1. Slip past the size limit. PHP enforces post_max_size against the declared Content-Length header. Requests sent with chunked encoding or without a usable length can deliver more data than the limit intends.
  • 2. Exhaust memory cheaply. A crafted multipart/form-data body — many file parts with empty filenames and deeply nested field names — makes PHP allocate far more internal structures than the body size suggests. Researchers exhausted the default 128 MB memory_limit with a body under 8 MB.
  • 3. Hit the half-built table (CVE-2026-109618). Inside PHP's hash-table insert routine, the element counters are incremented before the key is allocated. If that allocation is the one that fails, the table contains a half-initialised entry that teardown still treats as live.
  • 4. Leave stale state behind (CVE-2026-109619). Session upload progress — on by default — starts session handling during multipart parsing, before the application runs. A fatal error at that moment frees the request's memory but leaves session globals pointing into it. The next multipart request on the same worker reads and destroys those stale values.
  • 5. Turn corruption into code execution. By shaping what reclaims the freed memory, attackers convert these bugs into controlled memory writes and, ultimately, arbitrary code execution as the web server user.

The bugs have a long history. Memory-limit-based attacks on PHP were first explored back in 2004; a 2020 bug report about out-of-memory errors during long multipart uploads was treated as harmless; and a 2024 audit flagged a related issue without proving exploitability. PHP2Shell is where those earlier clues finally turned into reliable remote code execution paths.

Different paths for different server setups

Apache with mod_php is the easiest target. PHP still runs its shutdown code even when request start-up fails, so the corrupted data is touched before any application code executes — the page being requested doesn't matter. Apache also reuses worker processes, which keeps stale state alive for the next request.

PHP-FPM kills a worker that fails during start-up, which blocks the simplest path. The researchers instead needed a fatal error after start-up, which they found in PHP's unserialize decoder. That route requires an application that decodes data after start-up — via session_start(), session_decode(), unserialize() or wrappers like WordPress's maybe_unserialize() — which in practice covers a great many real applications.

Potential Impact

Calif reports confirmed pre-authentication RCE against default deployments of WordPress, Drupal, Joomla, MediaWiki, Roundcube, Magento, phpMyAdmin, Nextcloud, Laravel, Symfony and WHMCS. A successful attacker can gain:

What's at Stake
  • Code execution as the web server user — enough to read and modify the site and its files
  • Theft of database credentials, API keys and secrets from config files or leaked memory
  • Persistent backdoors (webshells, cron jobs) that survive the PHP patch
  • Customer data exposure from site databases, plus SEO spam, malware hosting or defacement
  • On shared or poorly isolated hosts, a stepping stone to neighbouring sites and internal systems

The scale is enormous. Estimates of internet-exposed PHP hosts range from roughly 1.3 million potentially vulnerable systems to more than 2.2 million PHP hosts overall — and CybelAngel estimates that 59% of them run PHP versions for which no official fix is coming.

Who Is Affected?

Every PHP installation that serves web requests. PHP lists PHP-FPM, Apache mod_php, php-cgi, FrankenPHP and LiteSpeed as affected, and rates mod_php as the highest risk. The vulnerable code paths go back to PHP 5.4.0 (2012).

PHP branchStatusWhat to do
8.5.xVulnerable before 8.5.12Update to 8.5.12 or later
8.4.xVulnerable before 8.4.27Update to 8.4.27 or later
8.3.xVulnerable before 8.3.36Update to 8.3.36 or later
8.2.xVulnerable before 8.2.35Update to 8.2.35 or later
7.4, 8.0, 8.1Vulnerable — end of lifeNo official release. Use a vendor/distro backport, PHP's minimal source backports, or upgrade to 8.2+
5.4 – 7.3Vulnerable — end of lifeNo fix exists. Upgrade, or isolate from the internet
Check the package, not just php -v. Linux distributions and LTS vendors received patches in advance and often backport fixes without changing the upstream version number. cPanel, for example, shipped the fix in EA4 including backports to ea-php74, ea-php80 and ea-php81. Confirm against your vendor's advisory.

Timeline and Exploitation Status

PHP2Shell was meant to follow a quiet, coordinated disclosure. Instead, the CVE identifiers leaked on Hacker News a day early, and the PHP team pulled the release forward. Reports on real-world exploitation still conflict, so we present them side by side.

Date (2026)What happened
Oct 17Amazon Threat Intelligence observes a php2shell exploitation attempt on its MadPot honeypots — four days before disclosure
Oct 20CVE IDs leak via a (later deleted) Hacker News post; PHP issues an advance notice; CERT-EU publishes an advisory
Oct 21PHP releases 8.5.12, 8.4.27, 8.3.36 and 8.2.35 at 14:00 UTC; Calif and Wiz publish technical details; CISA issues an alert; Cloudflare deploys WAF rules for all plans
Oct 21–22Cloudflare reports "early attacks emerging"; watchTowr reports exploitation attempts on its honeypots; multiple public proof-of-concepts appear
Oct 23Neither CVE is yet in CISA's Known Exploited Vulnerabilities (KEV) catalog

Where things stand: Amazon describes exploitation as now broad and multi-actor. Rapid7 and Huntress had not confirmed successful in-the-wild compromises, and Rapid7 found the public proof-of-concepts work only against narrow combinations of OS, PHP version and web server. The PHP team said at release that it had not identified a functional public exploit. That gap won't last — treat the current difficulty as a patching window, not a reason to wait.

Mitigation and Remediation

PHP is unambiguous: updating to a fixed release is the only complete fix. Configuration changes reduce exposure, but none makes a vulnerable installation safe.

Recommended Response
  • Inventory every PHP install — including PHP bundled inside vendor appliances, control panels, monitoring tools and container images, not just your obvious web servers.
  • Patch internet-facing systems first, starting with Apache + mod_php, to 8.5.12, 8.4.27, 8.3.36 or 8.2.35 (or your vendor's backported package).
  • Restart every PHP worker after updating — PHP-FPM pools, Apache, LiteSpeed. Old workers keep running vulnerable code.
  • Plan your way off PHP 8.1 and older. CISA advises taking unpatchable PHP systems offline; at minimum, place them behind a VPN or WAF.
  • If you can't patch today, apply the interim mitigations below and patch as soon as you can.

Interim mitigations (buy time only)

SettingAddressesNotes
session.upload_progress.enabled=0CVE-2026-109619 (session path)Must be set in php.ini, the FPM pool or server config. ini_set() and .user.ini apply too late.
memory_limit=-1CVE-2026-109618Set so applications can't override it. Removes the OOM trigger, but raises the risk of real memory exhaustion — pair with request limits.
fatal_error_backtraces=0CVE-2026-109619 (PHP 8.5)Closes a confirmed PHP 8.5-specific path; on by default in 8.5.
post_max_size / upload limitsBoth (reduces attack surface)Keep as small as your app allows; at the reverse proxy, cap request size, multipart part counts and nesting depth — including chunked requests.
WAF rulesKnown vectorsCloudflare and others ship rules, but only for traffic routed through them, and only for known patterns.
Mitigation pitfalls. Restart all workers after any change. Don't rely on RLIMIT_AS/RLIMIT_DATA — they can trigger the very allocation-failure path you're trying to avoid. Container/cgroup memory limits are an availability boundary, not a fix. And hiding errors with display_errors or @ does nothing to prevent stale-state access.

On shared or managed hosting?

If your site runs on shared hosting, cPanel/Plesk or a managed platform, your provider controls the PHP build — you can't patch the runtime yourself. Check which PHP version your site uses in your hosting panel, move off 7.x/8.0/8.1 to a supported branch, and ask your provider to confirm that the PHP build serving your account includes the October 21 fixes. Then focus on what you do control: keep your CMS, plugins and themes updated, and watch for unexpected file changes.

Detection and Threat Hunting

Exploitation attempts were seen from October 17, before disclosure, so investigations should look back at least that far. Before you change anything on a suspect server, preserve web server and PHP logs, configuration snapshots and suspicious files.

What to Look For
  • Unusual requests: very large, chunked or deeply nested multipart/form-data requests — especially to pages that never accept uploads.
  • Crashing workers: PHP processes hitting memory_limit fatal errors, segfaults or unexpected restarts in clusters.
  • Suspicious process trees: php-fpm, php-cgi, httpd or apache2 spawning sh, bash, python, perl, curl, wget or nc — or running recon such as whoami, id or uname -a.
  • Reverse-shell patterns in command lines, such as /dev/tcp/, mkfifo or fsockopen.
  • Persistence: new or modified PHP files in web roots and upload folders, new cron jobs, new user accounts, and unexplained outbound connections from PHP processes.

Scanner coverage is available from major vendors, including Tenable (Nessus plugin 369483), Rapid7 (remote and authenticated checks) and Qualys. Authenticated or agent-based scans are the most reliable, because unauthenticated scans can only see the PHP version if the server advertises it. And remember: a lack of log entries does not prove a server is safe.

Related: on October 23 the PHP Foundation published a further issue, CVE-2026-115560, which Rapid7 notes depends on non-standard configuration and currently has a mitigation but no patch. Keep an eye on the PHP security advisories for updates.

Key Takeaways for Security Teams

What This Teaches Us
  • Your runtime is part of your attack surface. A perfectly patched WordPress install is still exposed if the PHP underneath it is vulnerable. Track language runtimes like any other software.
  • End-of-life software is a standing risk. With most PHP hosts on versions that won't get an official fix, keeping runtimes on supported branches is the cheapest security control there is.
  • "Harmless" bugs age badly. An out-of-memory issue dismissed in 2020 became a building block for RCE six years later. Memory-safety bugs deserve a second look.
  • Defaults matter. Session upload progress is on by default and almost no one uses it. Turning off features you don't need shrinks the attack surface before the next bug appears.
  • Patched isn't the same as clean. With attempts seen before disclosure, check exposed servers for webshells and persistence — not just for the right version number.

In short: if you run PHP on anything that faces the internet, update to 8.5.12, 8.4.27, 8.3.36 or 8.2.35 now, restart your workers, and check for signs of compromise going back to October 17.


References

Tags: PHP2Shell CVE-2026-109618 CVE-2026-109619 PHP Remote Code Execution Use-After-Free WordPress Patch Management
Certifence Security Team
Threat Intelligence & Vulnerability Research

Not Sure If Your PHP Servers Are Exposed?

Our VAPT and incident response teams can find vulnerable PHP installs across your estate, verify your patches and mitigations, and hunt for webshells and persistence left behind by PHP2Shell exploitation attempts.

Talk to Our Team