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
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.
- 1. Slip past the size limit. PHP enforces
post_max_sizeagainst the declaredContent-Lengthheader. 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-databody — 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 MBmemory_limitwith 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:
- 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 branch | Status | What to do |
|---|---|---|
| 8.5.x | Vulnerable before 8.5.12 | Update to 8.5.12 or later |
| 8.4.x | Vulnerable before 8.4.27 | Update to 8.4.27 or later |
| 8.3.x | Vulnerable before 8.3.36 | Update to 8.3.36 or later |
| 8.2.x | Vulnerable before 8.2.35 | Update to 8.2.35 or later |
| 7.4, 8.0, 8.1 | Vulnerable — end of life | No official release. Use a vendor/distro backport, PHP's minimal source backports, or upgrade to 8.2+ |
| 5.4 – 7.3 | Vulnerable — end of life | No fix exists. Upgrade, or isolate from the internet |
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 17 | Amazon Threat Intelligence observes a php2shell exploitation attempt on its MadPot honeypots — four days before disclosure |
| Oct 20 | CVE IDs leak via a (later deleted) Hacker News post; PHP issues an advance notice; CERT-EU publishes an advisory |
| Oct 21 | PHP 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–22 | Cloudflare reports "early attacks emerging"; watchTowr reports exploitation attempts on its honeypots; multiple public proof-of-concepts appear |
| Oct 23 | Neither 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.
- 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)
| Setting | Addresses | Notes |
|---|---|---|
| session.upload_progress.enabled=0 | CVE-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=-1 | CVE-2026-109618 | Set 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=0 | CVE-2026-109619 (PHP 8.5) | Closes a confirmed PHP 8.5-specific path; on by default in 8.5. |
| post_max_size / upload limits | Both (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 rules | Known vectors | Cloudflare and others ship rules, but only for traffic routed through them, and only for known patterns. |
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.
- Unusual requests: very large, chunked or deeply nested
multipart/form-datarequests — especially to pages that never accept uploads. - Crashing workers: PHP processes hitting
memory_limitfatal errors, segfaults or unexpected restarts in clusters. - Suspicious process trees:
php-fpm,php-cgi,httpdorapache2spawningsh,bash,python,perl,curl,wgetornc— or running recon such aswhoami,idoruname -a. - Reverse-shell patterns in command lines, such as
/dev/tcp/,mkfifoorfsockopen. - 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.
Key Takeaways for Security Teams
- 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
- PHP.net — Security advisory: Critical remote code execution vulnerabilities, update now
- Calif — PHP2Shell technical write-up
- Rapid7 — CVE-2026-109618 and CVE-2026-109619: Critical Unauthenticated RCE in PHP
- Tenable — php2shell: Frequently Asked Questions
- watchTowr — PHP2Shell Remote Code Execution
- Huntress — Rapid Response: php2shell, Leaked Critical PHP Vulnerabilities
- Canadian Centre for Cyber Security — Alert AL26-026
- CybelAngel — 2.24M Internet-Facing PHP Hosts: What We Know About php2shell