PHP2Shell: Critical PHP RCE Flaws CVE-2026-109618 and CVE-2026-109619 plus Cloudflare WAF Protection

TL;DR: Quick Summary

PHP2Shell is the name for two critical memory safety flaws in the PHP engine core, tracked as CVE-2026-109618 and CVE-2026-109619 with CVSS v4.0 score 9.2. Both allow unauthenticated remote code execution and remote memory disclosure against any PHP web application, including WordPress, Drupal, Joomla, Magento, MediaWiki, Nextcloud, Laravel, and even a plain Hello World script. Every PHP version from 5.4 (released in 2012) through the October 2026 releases is affected. Fixed versions are PHP 8.5.12, 8.4.27, 8.3.36, and 8.2.35, released on 21 October 2026. PHP 8.1 and older get no official fix. Cloudflare deployed managed WAF and new full transaction response rules about 9 hours before public disclosure, enabled by default on all plans including Free. Patch PHP immediately, keep the WAF enabled, inventory every PHP install, block suspicious multipart uploads as a temporary measure, and watch for PHP workers spawning shells.


What Is PHP2Shell?

PHP2Shell is a pair of unauthenticated remote code execution vulnerabilities in the PHP language runtime itself that let a remote attacker run code as the web worker account or read live worker memory with passwords and tokens by sending crafted HTTP requests, with no login and no flaw in the hosted application required.

That definition matters because most site owners think in application terms: update WordPress, update plugins, update the theme. PHP2Shell sits one layer below all of that. The vulnerable code is the C code of the PHP interpreter that parses HTTP requests, manages request memory, and cleans up after fatal errors. If the interpreter is vulnerable, WordPress 7.1.2, Drupal 11.4.3, Joomla 6.1.4, Magento 2.4.9, MediaWiki 1.46.2, Roundcube 1.7.4, phpMyAdmin 5.2.3, Nextcloud 35.0.1, Laravel 13.11, Symfony 8.1, and WHMCS are all exposed even when their own PHP code is fully patched. Researchers confirmed pre-authentication RCE against stock Docker images of WordPress, Drupal, and Joomla, plus Magento and ten other stacks. A minimal test script that prints phpinfo is enough to prove exposure if it runs on a vulnerable PHP build.

Terminal showing PHP2Shell exploit analysis with Cloudflare WAF protection blocking CVE-2026-109618 and CVE-2026-109619 remote code execution
PHP2Shell targets the PHP engine below the application. Patch the interpreter, keep Cloudflare WAF protection enabled, and treat every PHP install as in scope until verified fixed.

At a Glance: The Two CVEs

Item CVE-2026-109618 CVE-2026-109619
Nickname Upload progress unserializer use after free, plus remote memory disclosure Fatal error backtrace use after free, plus OPcache type confusion
CVSS v4.0 9.2 Critical 9.2 Critical
Attacker login needed No, unauthenticated over HTTP No, unauthenticated over HTTP
Impact shown RCE on WordPress, Drupal, Joomla; application agnostic memory disclosure RCE on Drupal and WordPress via separate primitives
Root pattern Out of memory error interrupts request setup, partially initialized data later treated as valid Fatal error leaves request state pointing at freed memory, later request reuses the stale pointer
Leaks secrets Yes, freed worker heap returned inside a PHPSESSID response cookie Yes, heap use after free can disclose memory
Needs app session code No, works even when the app never calls session_start Depends on diagnostic or OPcache path, still pre-auth
Fixed in PHP 8.5.12, 8.4.27, 8.3.36, 8.2.35 PHP 8.5.12, 8.4.27, 8.3.36, 8.2.35

A Short History: From Heartbleed to PHP2Shell

Server side memory bugs keep returning because the internet runs on a small set of shared C codebases. Three earlier incidents explain why PHP2Shell got a name and a logo.

1. Heartbleed in OpenSSL (2014)

Heartbleed (CVE-2014-0160) let anyone read 64 KB chunks of server memory through a missing bounds check in the TLS heartbeat extension. Passwords, cookies, and private keys leaked with no trace in normal logs. PHP2Shell revives the same fear: CVE-2026-109618 returns attacker sized regions of live PHP worker memory inside a normal looking Set-Cookie response, similar in spirit to Heartbleed but through PHP request cleanup instead of TLS.

2. Shellshock in Bash (2014) and Log4Shell in Log4j (2021)

Shellshock showed that a parser far below the application (environment variable parsing in Bash) could give remote shells across DHCP, CGI, and SSH vectors. Log4Shell showed that one logging library buried in thousands of Java products could force the whole industry to hunt for every bundled copy. PHP2Shell combines both lessons. The parser is PHP request startup code that runs before any application check such as WordPress maintenance mode, and PHP itself is buried inside shared hosting panels, vendor appliances, Docker images, NAS boxes, and control panels like cPanel and Plesk that owners forget contain php.exe or php-cgi.

3. Why the flaws hid for over a decade

The vulnerable request lifecycle code dates to PHP 5.4.0 from 2012. Turning a crash into reliable RCE required chaining several bugs and adapting to each target memory layout, PHP version, SAPI, and CMS. Wiz Research states that frontier AI models made that manual grind practical: Wiz Atlas plus Gemini 4 Argon and GPT-5.6 Sol helped find the flaws, adapt exploits across WordPress, Drupal, and Joomla in hours, build detections, and verify the vendor patch. Calif researcher Ryan Austin independently found multiple RCE paths, and OpenAI contributed to discovery and patch verification. The economics changed. Complexity alone no longer protects old code.

Timeline of Disclosure

Date in 2026 Event
1 Aug Calif finds multiple PHP RCE paths
11 Aug Calif reports the first bug to PHP, coordinated disclosure starts
19 Aug Wiz Research discovers the first flaw with Atlas, Gemini 4 Argon, GPT-5.6 Sol
20 to 21 Aug Wiz confirms unauthenticated RCE against Drupal, then WordPress
24 Aug Wiz reports to the PHP security team
21 Sep PHP acknowledges reports and starts a coordinated fix
20 Oct morning Leak: Hacker News post claims two critical PHP RCEs, post removed, screenshots spread, watchTowr confirms the leak is real
20 Oct PHP posts advance notice, emergency release set for 21 Oct 14:00 UTC, warns it may ship earlier if details go public
21 Oct 03:02 UTC Cloudflare managed WAF protection goes live by default on all plans, about 9 hours before disclosure
21 Oct 07:43 UTC Cloudflare reports early attack traffic in the wild
21 Oct around 13:30 to 14:00 UTC (9:30 am ET) PHP releases fixed versions 8.5.12, 8.4.27, 8.3.36, 8.2.35; Calif, Wiz, OpenAI, and PHP Foundation publish writeups
21 Oct onward Public exploit tool PHP2Shell circulates, mass scanning expected, WAF analysts tune rules

Technical Deep Dive: How PHP2Shell Works

All four reported primitives share one theme: a fatal error during a request, most often out of memory when crossing memory_limit, interrupts native C code before cleanup finishes. The request heap is destroyed but some global pointer still points at the freed block. A later request handled by the same worker trusts the stale pointer before normal initialization resets it.

Affected SAPIs include PHP-FPM, Apache mod_php with prefork workers, php-cgi, FrankenPHP, and LiteSpeed. Default configurations are vulnerable. Application logs may show little because the exploit runs below application code.

CVE-2026-109618: Upload Progress Unserializer and Memory Disclosure

PHP parses RFC1867 multipart/form-data bodies during request startup, before normal module initialization. The session upload progress handler can initialize session state at this early stage and publish a session ID in the PS(id) global. If an out of memory error aborts the request, PHP destroys the request heap but may leave PS(id) pointing at the freed allocation.

On a later multipart request handled by the same worker, the upload progress cleanup path runs before normal session init resets the pointer. PHP trusts the stale pointer and length as a live zend_string and URL encodes reclaimed heap bytes into a PHPSESSID response cookie. That’s the Heartbleed style leak. It works even when the application never calls session_start, so no WordPress or plugin setting can switch it off.

The same family includes an upload progress unserializer use after free. Decoder bookkeeping lives in BG(unserialize). A fatal allocation failure interrupts the path, destroys the heap, and leaves the global unserializer state published. A later request reclaims that memory with attacker controlled bytes and PHP treats it as live decoder state, which gives a strong memory corruption primitive. Wiz combined disclosure plus corruption to remove address uncertainty and reach RCE on WordPress, Drupal, and Joomla.

CVE-2026-109619: Fatal Backtrace and OPcache Type Confusion

Two related primitives share this CVE number.

First, PHP keeps the backtrace of the most recent fatal error in EG(last_fatal_error_backtrace). A fatal out of memory error can destroy the request heap without undefining that executor global. The worker survives with a dangling pointer. If the same worker emits a diagnostic early in the next request, it touches the pointer before the executor reinitializes the state, then destroys or updates the dangling backtrace and follows attacker reclaimed memory.

Second, OPcache persists compiled structures in shared memory and assigns indices into per worker runtime pointer maps. Workers coordinate through a shared frontier. During zend_accel_script_persist, PHP advances the process local CG(map_ptr_last) frontier and only later publishes the shared frontier. An allocation failure between those two steps leaves the local advance in place with partially persisted objects pointing at slots the shared state still considers free. When another worker later reuses a slot for a different runtime object, stale shared metadata resolves to the wrong type. That cross worker type confusion corrupts shared OPcache state. Wiz used it for unauthenticated RCE against WordPress.

PHP notes there are other tracked and likely untracked variants of the same root pattern. The official patch fixes the core lifecycle instead of blocking single payloads, which is why updating PHP is the only complete remediation.

Cloudflare WAF Protection: What the 21 October Blog Post Announced

Cloudflare published Cloudflare deploys protections against php2shell vulnerability on 21 October 2026. The post is worth reading in full because it documents a new WAF capability, not just new signatures.

Key points from the Cloudflare announcement:

  • Protection went live at 21 October 03:02 UTC by default for customers using the managed WAF, on Free and paid plans. No action was needed to get initial coverage.
  • Cloudflare joined a coordinated effort with the PHP Foundation, OpenAI, Wiz, Automattic, Akamai, AWS, Fastly, Google, Imperva, Microsoft, Vercel, and others. Rules were developed and deployed since early October 2026.
  • Early exploit traffic was already observed before the official 14:00 UTC release because details leaked on 20 October. Attackers mutated payloads to try bypasses. Cloudflare tracked match volume and cross checked it against rule logic.
  • Request only rules weren’t enough. Request data alone often can’t separate an exploit from legitimate traffic with confidence. The origin response adds context that shows whether an exploit succeeded, which reduces false positives.
  • The answer is full transaction detection, a new Cloudflare WAF capability that combines signals from the request and the response inside the same HTTP transaction. A matching full transaction rule can block the origin response before it reaches the requester. PHP2Shell is the first managed detection released with this capability.
  • Customers should still patch PHP. WAF is defense in depth. Analysts continue to monitor and update rules as new techniques appear. Track the WAF changelog.

Cloudflare Rule Tables Published in the Post

Free plan, Cloudflare Managed Free Ruleset (ruleset ID 77454fe2d30c4220b5701f6fdfb893ba):

Rule description Rule ID
Generic Rules – Anomalous Execution – 1 4e315666e8e344cdb64139a3b5ccf32f
Generic Rules – Anomalous Execution – 2 00c10e6cc4da4bb08722adeebcd95984
Generic Rules – Anomalous Execution – 3 48ddf592361e4fb97a8a59abe2d613fa
Generic Rules – Anomalous Execution – 4 3556683d512a47f293789c524b1ac4c6
Generic Rules – Anomalous Execution – 5 da07c85852e34625b48cef6ede46c
Generic Rules – Anomalous Execution – 6 19373a83abb840e18ab3ce5a7975ce1b
Generic Rules – Anomalous Execution – 7 07f0b6ddaabf40b1b2042dade8d6f413

Paid plans (Pro, Business, Enterprise), Cloudflare Managed Ruleset (ruleset ID efb7b8c949ac4650a09736fc376e9aee), review deployment in block mode:

Rule description Rule ID
Generic Rules – Anomalous Execution – 1 c1d409ad838f47f54438d2cf438d5dd
Generic Rules – Anomalous Execution – 2 f9a45927414245c3ad0f24e1a0c2f64
Generic Rules – Anomalous Execution – 3 771c654ad1e4f5da7482f4e1545d3c4
Generic Rules – Anomalous Execution – 4 217005865f0145f392300bac212afcc95
Generic Rules – Anomalous Execution – 5 38ef82e7ea594e17bd67c376e9aee2b
Generic Rules – Anomalous Execution – 6 4148ae686dfbdb0487fab9f3cdb9a073
Generic Rules – Anomalous Execution – 7 1389aa25961743781ccf149c48144635

New Cloudflare Managed Response Firewall Default for all plans including Free:

Rule description Rule ID
Default block for High confidence Signatures afffe22785674c80a31875c848d2242a

Cloudflare notes the response rule descriptions will be updated soon. To review blocks, open Security, Security Analytics, Events in the dashboard, filter by the rule IDs above, and inspect matched request, action, and path. Scope the Managed Ruleset to relevant application paths if tuning is needed, following the deploy the Managed Ruleset guide.

Why Full Transaction Detection Matters for Site Owners

Traditional WAF rules only see the inbound request. PHP2Shell payloads abuse normal looking multipart uploads and memory pressure, which shared hosting panels, WordPress media uploads, and contact forms generate all day. Blocking on request shape alone would either miss variants or break uploads.

By also scoring response signals (anomalous execution markers, leaked worker memory patterns, high confidence exploit success indicators), Cloudflare can block the origin response before it reaches the attacker while letting normal uploads pass. For a ham running a WordPress blog, a DX cluster web view, or a club logbook behind Cloudflare, that means Free plan protection without writing custom rules, as long as the managed ruleset stays enabled and in block or managed challenge mode.

Are You Affected? Check These Cases

  • Any internet facing server running PHP 5.4 or later for web requests is in scope until patched, including PHP-FPM with nginx or Apache event MPM, Apache mod_php prefork, php-cgi, FrankenPHP, and LiteSpeed.
  • Patch coverage stops at PHP 8.2. Supported fixed releases are 8.5.12, 8.4.27, 8.3.36, and 8.2.35. PHP 8.1 and older, including the still common 7.4 and 8.0 and 8.1 builds, get no official update. Some Linux distributions and LTS vendors backport fixes, and PHP published minimal source backports for 7.4, 8.0, and 8.1 for operators who build from source. If your host can’t backport, plan an upgrade to 8.2 or newer.
  • Remi repository users on RHEL family systems should note the PHP Foundation warning that updated rpms.remirepo.net packages weren’t available on release day. Switch to distribution packages or build from source if the maintainer repo lags.
  • Hidden PHP counts. Inventory web servers first, then hunt for bundled PHP in vendor appliances, Windows tools shipping php.exe or php-cgi.exe, NAS apps, Docker images tagged wordpress:latest or drupal:latest or joomla:latest from before the fix, and anything running WordPress, Drupal, Joomla, Magento, MediaWiki, Roundcube, phpMyAdmin, Nextcloud, or WHMCS.
  • Shared hosting customers should ask the provider for the exact PHP build date and whether the 21 October security release or a backport is installed. A control panel PHP version selector isn’t proof until the provider confirms the underlying binary is patched.

What To Do Now: Patch First, Mitigate Second

1. Update PHP immediately

  • Update internet facing systems first to 8.5.12, 8.4.27, 8.3.36, or 8.2.35 from php.net downloads. Check your Linux distribution or LTS vendor for updated packages, since many received patches ahead of publication.
  • Restart PHP-FPM pools, Apache, or the container after updating, then verify with a phpinfo page or php -v on the exact SAPI that serves web traffic, not just the CLI binary.
  • Keep Cloudflare managed WAF enabled while patching. WAF plus fast patching is the combination Cloudflare, PHP, Wiz, and Sansec all recommend.
  • Schedule upgrades for EOL branches. PHP 8.1 gets no official fix, only a source backport branch. Treat 8.1, 8.0, 7.4, 7.x, and 5.x as guilty until reinstalled on a supported branch.

2. Temporary mitigations if you cannot patch within the hour

These are partial and buy time only. They don’t replace the PHP update. Sansec and PHP stress this point because several large Dutch sites briefly went offline as a precaution on release day.

  • Block multipart/form-data at the web server. Every known trigger is a multipart request, the format browsers use for file uploads. PHP parses that body before application code runs.

For nginx, inside every server block that passes to PHP:

if ($http_content_type ~* "multipart/form-data") {
    return 403;
}

Then run nginx -t and reload.

For Apache, inside every VirtualHost that serves PHP:

RewriteEngine On
RewriteCond %{HTTP:Content-Type} multipart/form-data [NC]
RewriteRule ^ - [F]

Then reload Apache. This breaks file uploads such as product images in Magento admin or media uploads in WordPress. Some cart and checkout forms also submit as multipart, so place a test order. Remove the rule after updating PHP.

  • Go offline or read only if the risk justifies it. PHP core developer Gina Peter Banyard called taking the server offline the most sensible option before the patch. Stop PHP-FPM and serve a static maintenance page. Note that Magento and WordPress maintenance modes don’t help, because PHP parses each request before the application checks the maintenance flag. If full offline is too much, have the web server reject every method except GET and HEAD so visitors can read but can’t log in or order:
if ($request_method !~ ^(GET|HEAD)$) {
    return 503;
}
  • Adjust PHP settings with care. PHP advisories mention turning off session upload progress and removing the memory cap as exposure reducers:
session.upload_progress.enabled = 0
memory_limit = -1

With mod_php set them in php.ini or a conf.d drop in and restart Apache. With PHP-FPM set them per pool, for example in /etc/php/8.3/fpm/pool.d/www.conf:

php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[memory_limit] = -1

Reload the FPM workers and confirm values in a page served by PHP-FPM, not on the CLI. Banyard warned that disabling upload progress alone isn’t enough, and memory_limit -1 lets one request consume all server memory. Combine these with the web server blocks above, watch memory use, and restore normal limits after patching.

  • Restrict uploads and limit sizes even after basic mitigation. Smaller post_max_size and upload_max_filesize plus strict WAF upload rules reduce memory pressure paths but don’t fix the engine.

3. Detect and hunt for exploitation

  • Watch for unusual multipart POST bursts followed by HTTP 500 responses, memory limit errors, or PHP worker churn.
  • Alert on PHP workers spawning shells or tools: sh, bash, cmd.exe, powershell.exe, python, perl, curl, wget, nc, certutil.exe, plus reverse shell strings such as /dev/tcp/, fsockopen, mkfifo, and quick recon commands such as whoami, id, uname -a, or ipconfig from a web worker parent like php-fpm, php-cgi, httpd, or apache2.
  • On Linux servers without endpoint detection, Florian Roth published a free process-watcher config for this incident with an observe mode quick start.
  • If you find a hit, isolate the server, preserve web and PHP logs, and hunt for webshells and new files in the web root, new cron jobs, scheduled tasks, and new accounts. Assume leaked worker memory may contain session tokens, API keys, and certificates, so rotate secrets after rebuilding on fixed PHP.

Comparison: PHP2Shell Against Other Internet Scale Flaws

Flaw Year Layer Transport Secret leak RCE Fix posture
Heartbleed CVE-2014-0160 2014 OpenSSL heartbeat TLS heartbeat request Yes, 64 KB per heartbeat No direct RCE Update OpenSSL, revoke certs
Shellshock CVE-2014-6271 2014 Bash env parsing CGI, DHCP, SSH env Limited Yes, command run Update Bash, block env vectors
Log4Shell CVE-2021-44228 2021 Log4j JNDI lookup Log strings Sometimes via exfil Yes, remote class load Update Log4j, remove JndiLookup
PHP2Shell CVE-2026-109618 2026 PHP request lifecycle Multipart HTTP POST Yes, worker heap in cookie Yes, pre-auth Update PHP engine, WAF response rules
PHP2Shell CVE-2026-109619 2026 PHP fatal error plus OPcache Later HTTP request on same worker Yes, heap disclosure Yes, pre-auth Update PHP engine, WAF response rules

The practical takeaway repeats across all five rows. Shared runtime code means one fix location but thousands of discovery locations. Inventory matters as much as patching.

Practical Example: Hardening a Live WordPress Site on Old PHP

Many ham radio sites, including WordPress blogs that host logbooks, cluster maps, and firmware download pages, run on shared FreeBSD or Linux hosts where the PHP version is controlled by the hosting admin, not the site owner. A common real case in October 2026 is WordPress running on PHP 8.1.29, which is end of life for official PHP updates and therefore has no 8.1 fix for PHP2Shell, only a source backport branch.

If you are in that position, the playbook used on production WordPress estates was:

  • Confirm the exact build through the edge to the origin: check response headers, a phpinfo probe file removed right after use, and the FPM pool that actually serves the vhost.
  • Ask the host admin to rebuild with the backport branch or upgrade to 8.2.35 or newer with extension parity checked.
  • While waiting, keep Cloudflare managed WAF enabled and add a narrow virtual patch at the edge: challenge or block anonymous multipart POSTs and very large anonymous POST bodies, while logged in authors and normal GET traffic pass through. One tested pattern blocks anonymous requests that are multipart or declare Content-Length of 1 MB and above, which shrinks both the upload progress path and the out of memory path without breaking media uploads for authors.
  • Remember limits: chunked POSTs without Content-Length bypass size checks, so only a PHP update is a complete fix. Monitor managed rule hits, keep backups verified, and recheck the PHP version after the host confirms the rebuild.

Limitations and Honest Notes

  • Cloudflare WAF helps but can’t see inside encrypted origin responses it doesn’t terminate, and can’t fix leaked secrets already exposed before rules went live at 03:02 UTC. Rotate keys if exposure is plausible.
  • Multipart blocks break legitimate uploads. Document the exception window, tell editors and store managers, and remove the block after patching.
  • Memory_limit -1 is risky on small VPS and Pi hosts common in ham shacks. One large request can trigger the OOM killer and take down Dire Wolf, DX cluster clients, or logging stacks sharing the box.
  • Third party patches floating on GitHub for EOL PHP may help builders from source, but Huntress and others note they can’t vouch for every fork. Prefer distribution packages, LTS vendor backports, or official source builds, tested on a staging copy first.
  • AI generated exploit tooling cuts both ways. Defenders can now reproduce and validate faster too, which is why coordinated disclosure included Cloudflare, AWS, Google, Fastly, Akamai, Imperva, Microsoft, and Vercel mitigations alongside the PHP release.

Frequently Asked Questions

What is PHP2Shell in one sentence?

PHP2Shell is a pair of critical unauthenticated PHP engine flaws, CVE-2026-109618 and CVE-2026-109619, allowing remote code execution and worker memory disclosure through crafted HTTP requests.

Which PHP versions fix PHP2Shell?

Fixed releases are PHP 8.5.12, 8.4.27, 8.3.36, and 8.2.35 from 21 October 2026. PHP 8.1 and older have no official fix.

Does Cloudflare block PHP2Shell on the Free plan?

Yes. Cloudflare enabled managed request rules plus new full transaction response rules by default on all plans including Free from 03:02 UTC on 21 October 2026.

Can a plugin or WordPress update fix PHP2Shell?

No. The flaws are in the PHP interpreter below the application. You must update PHP itself and keep WAF protection enabled.

What should I do if my host still runs PHP 8.1?

Ask for a backport rebuild or upgrade to 8.2.35 or newer. Until then, isolate the host, block anonymous multipart uploads at the edge, limit POST sizes, and monitor PHP workers.

Sources and Further Reading

73 de 9M2PJU

Post Comment