Executive summary
PHP2Shell is the name given to two critical vulnerabilities in the PHP engine, CVE-2026-109618 and CVE-2026-109619, both rated 9.2 on CVSS 4.0. Either one allows an unauthenticated attacker to execute code on the web server with the PHP process’s privileges, before the application has run a single line. Because the flaws sit in the runtime rather than in any framework or plugin, every PHP application served over HTTP is in scope: WordPress, Drupal, Joomla, Laravel, Symfony, Magento, custom code and the admin panel nobody has looked at since 2019.
PHP published fixed releases on 21 October 2026: 8.5.12, 8.4.27, 8.3.36 and 8.2.35. PHP 8.1 and older are end of life and receive no fixed release from the PHP project, though the security team published minimal source backports for 7.4, 8.0 and 8.1 and the major Linux distributions shipped patched packages for their supported branches. CISA added both CVEs to its Known Exploited Vulnerabilities catalog on 26 October after honeypot operators confirmed successful remote code execution, and set a 29 October deadline for US federal civilian agencies.
FireCompass research across 1,000,000+ assets found that one week after the fix, 65 percent of organisations assessed still had at least one exposed application, and that 48 percent of those exposures disclosed no PHP version at all. If you take one thing from this guide, take this: a clean X-Powered-By header is not a clean result, and a dirty one is not yet a finding.
1. What PHP2Shell is
PHP2Shell is two separate bugs with one shared property: both corrupt the PHP engine’s internal state during request handling in a way that a remote, unauthenticated attacker can steer into code execution.
CVE-2026-109618, remote code execution via out-of-memory corruption. When PHP runs out of memory while it is still setting up a request, the out-of-memory handler interrupts execution part way through. Request cleanup then runs against data structures that were only partially initialised, and it trusts them. An attacker who can make PHP hit its memory limit at exactly the wrong moment, which a large or deliberately complex multipart request body can do, turns that cleanup into memory corruption they control. The PHP security team validated unauthenticated RCE against Apache mod_php with a default memory_limit, and public reporting describes a working chain that leaks worker memory through an oversized cookie dump, derives function addresses from the leak to defeat ASLR, and lands in zend_call_function() with a command of the attacker’s choosing.
CVE-2026-109619, remote code execution via stale request-owned global state. PHP keeps some request-scoped data in process-global state. If the memory behind that data is freed but the global reference survives, the next request handled by the same worker picks up a dangling pointer. The confirmed path runs through session upload progress, a feature that is on by default since PHP 5.4 and that most applications never use. On PHP 8.5, fatal error backtraces provide a second confirmed path. The result is a use-after-free that an attacker can convert into memory disclosure and then code execution.
CVE-2026-115560, the third advisory. On 23 October the PHP project published an informational advisory for a separate, configuration-dependent issue in session upload progress involving the session serialize handler. It affects the fixed releases as well. PHP’s recommendation is the same mitigation as for 109619, session.upload_progress.enabled = 0, until the next regular release carries a full fix. It is not a bypass of the 21 October patches, and reporting that describes it as one is wrong.
The two main bugs are not the same bug and they do not share a mitigation. Disabling session upload progress closes the confirmed 109619 path and the 115560 path. It does nothing for 109618. Treat them as two separate exposures with one shared fix: upgrade.
2. How the disclosure unfolded
The timeline matters because it explains why so many organisations were exposed a week later. The fix shipped into an environment where the exploit tooling was already running.
- Mid-August 2026. Researchers at Calif, using AI-assisted analysis, identify the first flaw. Wiz independently finds and reports both; OpenAI is also credited by the PHP Foundation. Coordinated disclosure begins with a public release date set for 22 October, 14:00 UTC.
- 17 October. Amazon Threat Intelligence later reports an exploitation attempt against a honeypot on this date, four days before public disclosure.
- 20 October, evening UTC. The CVE IDs leak on forums and social media with a wrong release time and a wrong CVSS score of 10.0, but no technical details. PHP publishes a pre-announcement and moves the release forward one day.
- 21 October, 03:59 UTC. Fastly records the first request from a tool with PHP2Shell in its name. By 07:41 the most widespread exploit kit is active. Cloudflare reports first attacks at 07:43, more than six hours before the fix.
- 21 October, 14:00 UTC. PHP releases 8.5.12, 8.4.27, 8.3.36 and 8.2.35. By then more than 100 source IPs have used PHP2Shell-branded tooling under more than two dozen tool names. Ubuntu, Debian, Red Hat and the major clouds ship packages, WAF rules and runtime patches the same day. CISA and the UK NCSC publish alerts; CISA notes it has not yet observed exploitation.
- 21 to 22 October. Fastly stores roughly 250,000 requests from PHP2Shell-named tools from about 3,200 IP addresses. HKCERT reports both CVEs exploited in the wild on 22 October.
- 22 October. FireCompass releases its non-intrusive PHP2Shell exposure scan and begins running it across customer environments.
- 23 October. PHP publishes the CVE-2026-115560 informational advisory. CISA’s KEV catalog still lists neither CVE.
- 24 October. Perplexity’s detection lead reports confirmed RCE against a honeypot running Apache mod_php on PHP 8.4.26, with an 800 KiB decoded cookie dump and a function address derived from it appearing in the execution payload.
- 26 October. CISA adds both CVEs to the KEV catalog with a 29 October deadline for federal civilian agencies. Dream Group reports a chained attack combining PHP2Shell with a Linux kernel privilege escalation (CVE-2026-46300) that compromised 25 servers across four countries, including a US government-affiliated environment. Wiz reports roughly a 67 percent drop in distinct exposed systems since disclosure.
From the leak to the KEV listing took six days. From the first exploit tooling to the fix took ten hours, in the wrong order.
3. Who is affected
Software
Every PHP SAPI that serves web requests: Apache with mod_php (rated highest risk in the official advisory, and the configuration against which RCE was first validated), PHP-FPM behind Nginx, Apache or Caddy, php-cgi, FrankenPHP and LiteSpeed. Switching from mod_php to PHP-FPM is not a mitigation; both are affected.
Wiz demonstrated unauthenticated RCE against current WordPress, Drupal and Joomla container images with no plugin or theme involved. The application on top is irrelevant to whether you are exposed. Only the runtime version matters.
Versions
Is my PHP version exposed?
Enter the version your server reports. The result applies to upstream PHP builds; on distribution-managed hosts confirm the package version (Step 4).
| PHP branch | Last vulnerable | First fixed | Status |
|---|---|---|---|
| 8.5 | 8.5.11 | 8.5.12 | Active support |
| 8.4 | 8.4.26 | 8.4.27 | Active support |
| 8.3 | 8.3.35 | 8.3.36 | Security support |
| 8.2 | 8.2.34 | 8.2.35 | Security support, EOL 31 December 2026 |
| 8.1 | all | none from PHP | EOL. Minimal source backport published; vendor packages available |
| 8.0, 7.4 | all | none from PHP | EOL. Minimal source backport published; vendor packages available |
| 7.3 and older, down to 5.4 | all | none | EOL. Treat as affected |
One detail that caught several teams: two builds of 8.4.27 exist. The 21 October build was superseded by a 22 October build. If you compiled from source or pulled a container image on the first afternoon, check the build date and not only the version string.
Vendor backports
Distributions patched their own package versions without changing the upstream version string. Ubuntu, for example, fixed PHP 8.1 on 22.04 in package 8.1.2-1ubuntu2.28, PHP 8.3 on 24.04 in 8.3.6-0ubuntu0.24.04.13 and, under Expanded Security Maintenance, PHP 7.4 on 20.04 and even PHP 5.5 on 14.04. A server on Ubuntu 22.04 will report PHP 8.1.2 in its headers whether or not the fixed package is installed. The version string cannot tell you; the package manager can.
This is the single largest source of both missed exposures and wasted effort in PHP2Shell response, and it is why Section 5 below separates “what the server says” from “what is actually installed.”
4. Exploitation status and what attack traffic looks like
Both CVEs are on CISA’s KEV catalog, which is the formal confirmation of exploitation in the wild. Before that listing, Cloudflare, Amazon, Hadrian, watchTowr, Previdian and Patchstack had reported widespread exploitation attempts; the KEV addition followed honeypot confirmation of successful code execution on a single-worker mod_php setup. The attack Dream Group reported is the one to plan around: PHP2Shell for initial access, a kernel privilege escalation for root, and a 25-server footprint across the United States, Japan, Taiwan and South Korea.
What the traffic looks like, from Fastly’s and Cloudflare’s published telemetry:
- Multipart
POSTrequests to/index.phpor/, often chunked with noContent-Length, with bodies padded by long runs of a single character to drive memory pressure. - Exploit kits that name themselves in the
User-Agent(php2shell-109618and variants) and use a recognisable multipart boundary string. Self-labelled tools are mostly probes rather than exploitation. - Two look-alike campaigns running at the same time: React2Shell (CVE-2025-55182) and wp2shell, a WordPress core RCE disclosed in July 2026. Fastly found that one widely shared “PHP2Shell signature,” the padded-body pattern, was 99.7 percent React2Shell traffic the day before the release. Rule those out before counting anything as PHP2Shell.
Exploitation success is not visible from the edge. PHP2Shell works by crashing or corrupting a PHP worker, so a successful attempt and a failed one can look identical in WAF logs. Confirmation lives on the host (Section 7).
5. How to find out whether you are exposed
Step 1: Inventory every PHP runtime, not every PHP application
The applications you know about are the easy part. The runtimes most often missing from an inventory are the ones the public trackers keep adding: staging and UAT hosts, hosting panels such as cPanel and Plesk, internal appliances with embedded PHP, bundled php-cgi.exe on Windows, secondary FPM pools, acquired applications and the phpMyAdmin instance behind an obscure path. Start with external discovery, then reconcile against what the CMDB says.
Step 2: Read what the server discloses
From outside, a PHP version can appear in Server, X-Powered-By or X-PHP-Version response headers, or on a reachable phpinfo() page (phpinfo.php, info.php, php_info.php). Presence of PHP without a version shows up as a PHPSESSID cookie, .php links and forms, CMS and framework markers, or PHP error text.
curl -sI https://app.example.com | grep -iE '^(server|x-powered-by|x-php-version):'
Compare any version found with the table in Section 3. Anything below the first fixed release for its branch is a candidate finding. Anything on 8.1 or older is a candidate finding with no upstream fix.
Step 3: Do not trust the header in either direction
Three traps turn a header check into a false result:
- Hidden versions.
expose_php = Offis standard hardening. Reverse proxies and CDNs stripX-Powered-By. In FireCompass’s data, 48 percent of confirmed exposures disclosed nothing. A missing version means “unknown,” never “safe.” - Fake versions. Catch-all routes return HTTP 200 for any
.phppath. Single-page applications serve the same shell for every URL. CMS, framework and dependency versions look like PHP versions. Request a random, nonexistent.phppath as a control and discard any response that matches it. In FireCompass’s data, about one in four raw header flags failed this check. - Backported versions. As Section 3 explains, a distribution-managed host reports the upstream version string after patching. A header reading 8.1.2 on Ubuntu 22.04 is either fully patched or critically exposed, and the header cannot say which.
Step 4: Confirm from the package and the process
On the host, the package manager and the running process are the sources of truth.
# Debian / Ubuntu
apt list --installed 'php*' 2>/dev/null | grep -E '^php[0-9.]+/'
# RHEL / Rocky / Alma
rpm -q php php-fpm
# Any host: what is actually serving requests
php-fpm8.3 -v # or php -v for mod_php
ps -eo pid,lstart,cmd | grep -E 'php-fpm|httpd|apache2'
Compare the installed package with the vendor’s fixed package version, not with the upstream fix line. Then check the process start time. The fix is live only once every PHP worker has been restarted; a fixed package with old workers is still exposed.
Step 5: Validate behaviour where the version is hidden
For applications that disclose nothing and sit on hosts you do not administer, version checking ends and validation begins. Public high-fidelity scanners such as Assetnote’s php2shell-scanner report a target as vulnerable when a probe produces a PHP memory-exhaustion error, a differential empty HTTP 500, a PHP-FPM worker failure, or an advertised unpatched version. They carry their own caveats: the Assetnote tool documents false positives on patched 8.4.27 and 8.3.36 at low memory_limit values or high max_multipart_body_parts, and its multipart probe is not something to point at production without authorisation and change control. This is the stage where FireCompass’s pentest agents did the work in the research sample, validating the affected runtime behaviour safely and attaching the evidence to each verdict.
6. Remediation
Upgrade. It is the only complete fix.
| Current branch | Move to |
|---|---|
| 8.5.x below 8.5.12 | 8.5.12 or later (check build date if on 8.4.27 from 21 October) |
| 8.4.x below 8.4.27 | 8.4.27 or later |
| 8.3.x below 8.3.36 | 8.3.36 or later |
| 8.2.x below 8.2.35 | 8.2.35 or later, and plan the 8.3 move before 31 December |
| 8.1 and older | Vendor-patched package if your distribution ships one; otherwise migrate to a supported branch |
On distribution-managed hosts:
# Ubuntu / Debian
sudo apt update && sudo apt install --only-upgrade '?name(^php[0-9.]+$)'
sudo systemctl restart apache2 # mod_php
sudo systemctl restart php8.3-fpm # FPM, adjust version
Restart every PHP worker, or reboot. unattended-upgrades installs the package within 24 hours but does not restart the application that uses it.
Legacy applications with no fix
For PHP 7.x and 8.0/8.1 outside a vendor’s support window, there is no upgrade path that keeps the branch. Options, in order of preference: migrate to a supported branch; move the application behind a vendor-maintained runtime (Ubuntu Pro ESM, Red Hat EUS) that ships backports; apply the PHP security team’s minimal source backport if you build from source; isolate the application behind authentication and a WAF while you decide; retire it. The decision is a business one, but it has to be made per application and recorded, because an unsupported branch will be below the fix line for every PHP vulnerability from here on.
Interim mitigations when the upgrade must wait
PHP’s advisory is explicit that none of these is a complete fix. Each stops one path at one cost. Apply them in php.ini, an FPM pool or server configuration, never with ini_set(), because the relevant settings are read before the request starts, and restart every worker afterwards.
| Mitigation | Stops | Costs | Setting |
|---|---|---|---|
| Disable session upload progress | Confirmed 109619 path, and 115560 | Upload progress bars, rarely used | session.upload_progress.enabled = 0 |
| Disable fatal error backtraces (8.5 only) | Second confirmed 109619 path | Backtraces in fatal error output | fatal_error_backtraces = 0 |
| Remove PHP’s memory ceiling | The OOM trigger for 109618 | Runaway requests are no longer stopped by PHP; set OS or container limits instead | memory_limit = -1 at an admin layer applications cannot override |
| Tighten request body limits | Reduces the 109618 OOM path | Breaks uploads larger than the limit | post_max_size = 8M, upload_max_filesize = 2M (adjust) |
| Block or size-limit multipart at the web server | The confirmed 109618 trigger including bodies with no length | Breaks every upload on the site | Web server or WAF rule |
| WAF virtual patch | Known exploit kit shapes | Nothing stops a reshaped payload | Cloudflare, Fastly, Cloud Armor and others shipped rules on 21 October |
FPM pool example:
php_admin_value[session.upload_progress.enabled] = 0
php_admin_value[post_max_size] = 8M
php_admin_value[upload_max_filesize] = 2M
Verify after the restart:
php-fpm8.3 -i | grep -E 'session.upload_progress.enabled|post_max_size|memory_limit'
Keep session.upload_progress.enabled = 0 after patching until the regular release that fully addresses CVE-2026-115560.
Verify the fix, then rescan
A fix is verified when a rescan after the worker restart shows the fixed version or fixed behaviour, not when the ticket says the package was installed. Record the evidence. Auditors, cyber insurers and regulators will ask for it, and the KEV listing makes PHP2Shell a named item in the next review.
7. Detection and threat hunting
Because success is invisible at the edge, hunt on the host.
- Child processes from PHP workers. Exploitation typically shows as
php-fpm,php-cgi,httpdorapache2spawningsh,bash,curl,wget,pythonorperl. Alert on any shell or downloader whose parent is a PHP worker. - Egress from PHP workers. A connect-back shell is an outbound connection from a process that should only answer inbound HTTP. Monitor worker-originated network connections.
- Worker crashes. Segfaults,
_exit(137)from the newmemory_hard_limit_percentguard in fixed releases, and FPM child respawn storms in the hours around 21 October are worth correlating with request logs. - Request patterns. Multipart
POSTto PHP endpoints with noContent-Length, padded bodies and known boundary strings. Baseline against the week before disclosure and split any increase by boundary orUser-Agentbefore attributing it, so that React2Shell and wp2shell traffic is not counted as PHP2Shell. - Memory disclosure artefacts. The confirmed RCE chain includes an oversized
Set-Cookieor cookie echo (hundreds of KiB) that leaks worker memory. Responses of that shape in your logs are a strong indicator of an attempt that got further than a crash. - Persistence. Web shells dropped into the document root, new cron entries and modified
.htaccessfiles are the usual follow-on. The Dream Group case shows attackers chaining to a kernel LPE immediately, so check for the CVE-2026-46300 patch state on any host that was exposed.
If you find evidence of exploitation, treat the host as compromised rather than as unpatched. Patching after the fact does not evict an attacker.
8. Free tools
- FireCompass Explorer. Free external discovery of your internet-facing assets, including the staging hosts, forgotten subdomains and admin panels a PHP2Shell response has to cover. Inventory is where every PHP2Shell response starts, and most teams discover during the response that theirs is incomplete. Start your free Explorer scan
- FireCompass Free AI Pen Test. A no-cost run of the FireCompass AI pentesting agents against an application of your choice, with proof of exploit on every finding. Request your free AI pen test
- FireCompass PHP2Shell Exposure Scan. The non-intrusive, production-safe check described in Section 9, available to customers and prospects on request. Email [email protected] to schedule it.
- Assetnote php2shell-scanner (open source). A command-line scanner that combines version checks with behavioural probes. Read its false positive notes before trusting a verdict and do not run it against production without authorisation.
- Vendor references. The PHP project’s advisory and the GitHub security advisories GHSA-w8hw-w9fx-j79w (109618) and GHSA-6wmf-4rv5-p3rp (109619); Ubuntu’s USN-8948-1 and USN-8948-2; CERT-EU and NCSC-NL’s operational trackers listing affected third-party products, which is where to check whether an appliance you run embeds a vulnerable PHP.
9. How FireCompass helped
FireCompass released its PHP2Shell exposure scan within one day of disclosure and ran it across the 1,000,000+ assets under its agents’ coverage. The scan is a non-intrusive version check: at most nine ordinary web requests per application, a standard browser User-Agent, bounded response reads, a fixed request budget, and early stop on rate limiting, blocks, errors or out-of-scope redirects. It never exploits, crashes, uploads to or fuzzes a target, and it stores no page bodies, cookie values or full headers.
Every verdict comes with a reason code and the exact request and response signal behind it, in one of four classes: CRITICAL (affected version advertised), POTENTIAL_MEDIUM (PHP present, version hidden), INCONCLUSIVE (access or network issues) and SAFE (fixed version, or PHP not detected). Control requests against a random, nonexistent .php path and the entry page filter out catch-all routes, single-page applications and soft-404s before anything is reported.
Where the version was hidden or possibly backported, the FireCompass pentest agents validated the affected runtime directly, which is how the research confirmed the 48 percent of exposures that a header check would have missed. For customers, the programme then ran through to closure: upgrade guidance per application, triage of legacy branches with no fix, interim safeguards where upgrades had to wait, backport confirmation so that teams neither patched twice nor marked a patched host as exposed, and a rescan after every fix so that closure was verified and documented. Support ran at three levels depending on need: advisory, a dedicated testing point of contact who tracked every finding to closure, and a dedicated customer success executive working in person with security, DevOps and application teams.
The research outcome is in the companion report: 65 percent of organisations exposed a week after the fix, 48 percent of exposures hidden from version checks, one in four raw header flags false, and 38 percent of affected organisations with five or more exposed applications.
10. Frequently asked questions
What is PHP2Shell?
PHP2Shell is the nickname for CVE-2026-109618 and CVE-2026-109619, two critical (CVSS 4.0 9.2) vulnerabilities in the PHP engine that allow unauthenticated remote code execution against any PHP application served over HTTP. Fixes were released on 21 October 2026.
Which PHP versions are affected by PHP2Shell?
Every release below 8.5.12, 8.4.27, 8.3.36 and 8.2.35, and every release of PHP 8.1 and older. Distributions have shipped patched packages that keep the old version string; check the package version, not the header.
Is PHP2Shell being exploited in the wild?
Yes. CISA added both CVEs to its Known Exploited Vulnerabilities catalog on 26 October 2026 after honeypot confirmation of successful code execution, and Dream Group has reported a chained attack that compromised 25 servers.
Does disabling session upload progress fix PHP2Shell?
No. It closes the confirmed path for CVE-2026-109619 and for the follow-on CVE-2026-115560. It does nothing for CVE-2026-109618. Upgrading is the only complete fix.
Am I safe behind a WAF or CDN?
Safer, not safe. Cloudflare, Fastly and Google Cloud shipped rules on 21 October and reported attackers reshaping payloads to get past them within hours. A WAF is a virtual patch for known exploit shapes, not a fix for the bug.
My server does not show a PHP version. Am I exposed?
Unknown, which is not the same as no. In FireCompass’s research, 48 percent of confirmed exposures disclosed no version. Confirm from the package manager and the running process, or validate behaviour.
I run WordPress, Drupal or Joomla. Does a CMS update help?
No. The vulnerability is in PHP, not in the CMS. Wiz demonstrated RCE against current images of all three with no plugin involved. Update the PHP runtime.
How do I prove to an auditor that we fixed it?
Keep the package version, the worker restart time and a rescan result after the restart, per application. The FireCompass scan produces exactly that record on rescan.
11. About FireCompass
FireCompass is an Agentic AI platform for autonomous penetration testing and red teaming across Web, API, and infrastructure. It discovers shadow assets and web applications, safely validates what is exploitable, and connects findings into multi-stage attack paths with near-zero false positives. Unlike traditional scanners, it discovers credential reuse, business-logic flaws, privilege escalation, and app-to-app or app-to-network lateral movement. It can operate autonomously or with expert-in-the-loop validation, with proof of exploit. FireCompass ranked #1 AI on HackerOne, has 30+ analyst recognitions across Gartner, Forrester, and IDC, and is trusted by Fortune 1000 enterprises.
12. Sources
PHP Foundation security advisory and release announcement, 21 October 2026, and informational advisory for CVE-2026-115560, 23 October 2026. GitHub security advisories GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp. Ubuntu, “php2shell: PHP critical vulnerability fixes available,” 21 October 2026. Fastly, “PHP2Shell: Finding the Needles in a 250,000 Request Haystack.” Cloudflare, Wiz and Amazon Threat Intelligence public statements, 21 to 26 October 2026. CISA Known Exploited Vulnerabilities catalog entries, 26 October 2026. Tenable, SOCRadar, Recorded Future, The Hacker News and RH-ISAC reporting, 22 to 28 October 2026. Assetnote php2shell-scanner documentation. CERT-EU and NCSC-NL operational trackers. FireCompass PHP2Shell Exposure Research, October 2026.
Find out which of your applications are exposed to PHP2Shell
Non-intrusive, production-safe, evidence on every verdict.
