PHP2Shell (CVE-2026-109618, CVE-2026-109619): What Actually Decides Whether You're Exposed
Someone was exploiting PHP2Shell four days before the world knew it existed. The settings everyone is passing around don't make a PHP server safe, and the version number doesn't tell you whether you're fixed. Two facts do.
Overview
If you run PHP, two facts decide whether PHP2Shell can reach you: whether your installed build contains the fix, and whether that PHP takes input from the network. Not your php.ini, and often not the version string your scanner reads. Whether you run mod_php or PHP-FPM changes which attacks have been demonstrated, not whether you're in scope.
PHP2Shell is two critical flaws in the PHP engine, CVE-2026-109618 and CVE-2026-109619, fixed in PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12 on 21 October 2026. Both allow unauthenticated remote code execution. In the demonstrated mod_php attacks, PHP processes the malicious request before any application code runs, so your application's login doesn't help. The flaws were found by researchers at Calif, Wiz and OpenAI, among others; Calif and Wiz say they used AI models in the work. Amazon's honeypots recorded an exploitation attempt on 17 October, four days before disclosure; details leaked a day early, and Cloudflare reported attack traffic against its customers before PHP's release. Amazon reports broad exploitation attempts against its honeypots, and says it's unclear whether any of them would have succeeded on real systems.
We investigated what actually decides exposure: PHP's advisories and code, the fix commits, the distributions' fixes, and each popular workaround. This is what we found.
What to do now
- Patch to 8.2.35, 8.3.36, 8.4.27 or 8.5.12, or your distribution's fixed package.
- Prove the fix is in the build you run. Check the package's changelog for the CVE IDs (commands below). Don't trust the version number alone: several distributions ship the fix under older versions.
- While you patch, reduce exposure, but don't call it safe. PHP's own advisory says its workarounds "reduce exposure to specific attack paths but do not make an installation safe".
- Watch for the signs listed under Detection.
- Keep
session.upload_progress.enabled=0until PHP's next regular release if your application switchessession.serialize_handlerat runtime. That's the only setup affected by CVE-2026-115560, a related bug PHP disclosed on 23 October (below).
How it works
PHP2Shell is one family of bugs with two IDs. On every supported branch, a single commit fixes both: "Avoid state corruption via bailout".
- CVE-2026-109618 ("RCE via OOM corruption"). When PHP runs out of memory, it aborts the operation in progress by jumping out of it. Some operations were only half finished at that moment. For example, inserting a value into an internal table counted the new entry before creating its key, so the abort left a counted entry with a garbage key, which request cleanup then read. PHP's advisory confirms remote code execution against Apache mod_php with default limits.
- CVE-2026-109619 ("RCE via stale global state"). PHP keeps some state per worker process. After a fatal error, part of that state could still point at memory the finished request had freed, and a later request on the same worker could use it. PHP confirms code execution through session upload progress on mod_php and PHP-FPM, and through fatal-error backtraces on PHP 8.5.
The fix stops aborting in the middle of an operation: an out-of-memory error now waits for a safe point, or, past a second and higher limit, ends the worker immediately. It also resets the leftover state earlier.
A related bug, CVE-2026-115560. On 23 October PHP published an informational advisory for a third issue in session upload progress that the current releases, including 8.5.12, don't fix. PHP calls it "an unlikely RCE vector": it needs an application that sets session.serialize_handler to php_binary or php_serialize in configuration, switches it to php with ini_set() before session_start(), and still has upload progress enabled. Applications that never change the serialize handler at runtime aren't affected. PHP will fix it in its next regular release; until then session.upload_progress.enabled=0 fully protects against it.
How we confirmed it
- One commit fixes both CVEs on each branch: 8.2
01a40e89fb, 8.33c832b523e, 8.4506e87fa7d, 8.531c0ea7d7f, each citing both PHP advisories (GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp). - The faulty pattern is still in the code after the fix. In PHP 8.2.35, the table insert still counts the entry before allocating its key (
Zend/zend_hash.c, lines 1048–1049). What changed is that an out-of-memory error no longer aborts mid-insert. - The trigger isn't only file uploads. The new test PHP added with the fix (
oom_request_parsing_next_request.phpt) reaches the out-of-memory condition during request parsing with an ordinaryapplication/x-www-form-urlencodedPOST, and Datadog's lab reproduction used the same kind of request. - Setting
memory_limit=-1doesn't remove the abort. In the unfixed code, a real allocation failure still takes the same abort path (Zend/zend_alloc.c, PHP 8.2.34). PHP's advisory says so too. - We compared the Debian, Ubuntu and CentOS Stream patches with the upstream fix. Debian ships the upstream release; Ubuntu's patch headers name the upstream fix commit; CentOS Stream's patches match the upstream fix and PHP's end-of-life backports. The other distributions' status in the table below comes from their own security trackers.
Timeline (UTC)
- 1 August 2026: Calif finds several independent paths to code execution; on 11 August it reports the first bug to PHP. Wiz also reported (both are credited in PHP's advisories).
- 17 October: Amazon's MadPot honeypots record a PHP2Shell exploitation attempt from a commercial anonymization network, four days before disclosure. Amazon: "it remains unclear how the actor acquired exploit information prior to disclosure".
- 20 October: the CVE IDs leak; PHP moves its release up a day (PHP Foundation, via Tenable).
- 21 October, 02:00–08:00: Amazon sees proof-of-concept exploits and more attempts against its honeypots; Cloudflare reports attack traffic against its customers.
- 21 October, from 13:34: PHP publishes advisories GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp and releases 8.2.35, 8.3.36, 8.4.27 and 8.5.12 (scheduled for 14:00), plus source backports for 7.4, 8.0 and 8.1.
- 21–22 October: distributions ship fixes (below). Amazon reports PHP2Shell is "now being broadly exploited in the wild", later reworded to "now seeing broad exploitation attempts in the wild"; Amazon also says it's unclear whether any attempt would have succeeded on real systems. CISA's assessment on the CVE records at publication time said exploitation "none". NVD has since added its own CVSS 3.1 score of 9.8.
- 23 October: PHP publishes an informational advisory for a related bug, CVE-2026-115560 (above). Red Hat ships a fix for RHEL 7 under Extended Life Cycle Support (RHSA-2026:88693). CISA's KEV catalog update that day still lists neither PHP2Shell CVE.
The four days that matter
Between 17 October, when Amazon's honeypots recorded the first exploitation attempt, and 21 October, when PHP published its advisories, there was nothing public to act on: no CVE, no advisory, no fixed version for a scanner to match. The fix already existed. PHP had it, and distributions received it in advance under embargo. Someone was exercising the exposure anyway.
This is the patchless window: a fix exists, but nothing public says so, so nothing that matches versions or signatures can flag you. In those four days, the defenders who could act were the ones who already knew which of their PHP servers took traffic from the internet, and could reduce exposure without a patch: isolate internet-facing PHP, filter request shapes at the edge, tighten limits.
The exposure exercise window has been collapsing for years. Here it went below zero: the attack came before the disclosure. Amazon draws the same lesson: start investigations from the earliest known exploitation, not the disclosure date, and don't depend on a signature for a specific CVE to know you're exposed.
Not every analyst reads the risk the same way. On 22 October Sansec said mass exploitation looks less likely than it expected on release day, because the public exploits don't work against a default PHP installation, while Amazon reports broad exploitation attempts against its honeypots. Both can be true: attempts are broad, and success depends on the build and how PHP is run.
Am I affected?
Exposure depends on your build, not the upstream version.
| Build | Status as of 25 October 2026 |
|---|---|
| Upstream 8.2.35, 8.3.36, 8.4.27, 8.5.12 and later | Fixed |
| Debian 13 trixie php8.4 8.4.27-1~deb13u1 (DSA-6574-1); Debian 12 bookworm php8.2 8.2.35-1~deb12u1 (DLA-4848-1); forky and sid php8.4 8.4.27-1 | Fixed |
| Ubuntu 24.04 php8.3 8.3.6-0ubuntu0.24.04.13; Ubuntu 22.04 php8.1 8.1.2-1ubuntu2.28; 26.04 php8.5 8.5.4-0ubuntu1.5; 26.10 php8.5 8.5.9-0ubuntu2.1 (USN-8948-1/-2) | Fixed, under version numbers that tools reading the upstream PHP version flag as vulnerable |
| Ubuntu Pro (ESM): php7.4 (20.04), php7.2 (18.04), php7.0 (16.04), php5 (14.04) | Fixes released |
| Chainguard and Wolfi php-8.2 8.2.34-r4, php-8.3 8.3.35-r4, php-8.4 8.4.26-r4, php-8.5 8.5.11-r4 | Listed fixed, under version numbers below the upstream fix |
| Alpine edge, v3.24 and v3.23: php83 8.3.36-r0, php84 8.4.27-r0, php85 8.5.12-r0; v3.22: php82 8.2.35-r0, php83 8.3.36-r0, php84 8.4.27-r0; v3.21: php82 8.2.35-r0 | Fixed (older Alpine branches: no fix recorded as of this date) |
| RHEL 8 php:7.4, php:8.2; RHEL 9 php, php:8.2, php:8.3; RHEL 10 php, php8.4 (RHSA-2026:87070, 87071, 87072, 87073, 87079, 87080, 87151); Oracle Linux 8, 9 and 10 (ELSA-2026-87070, -87071, -87072, -87073, -87079, -87080, -87151); AlmaLinux 8, 9 and 10 (ALSA-2026:87070, :87071, :87072, :87079, :87080) | Fixed packages released |
| RHEL 9 php:8.4 | Affected, no fix yet (Red Hat) |
| RHEL 7 (PHP 5.4) | Fixed for CVE-2026-109619 under Extended Life Cycle Support: php 5.4.16-48.el7_9.1 (RHSA-2026:88693, 23 October); not affected by CVE-2026-109618. The fixed package still reports PHP 5.4.16, so tools reading the upstream version flag it as vulnerable |
| Amazon Linux 2023 php8.2, php8.3, php8.4, php8.5 (ALAS2023-2026-3301/3302/3303/3304); Amazon Linux 2 php8.2 (ALAS2PHP8.2-2026-015); Amazon Linux 2027 php8.5 (ALAS2027-2026-243) | Fixed packages released; each advisory lists both CVEs |
| Amazon Linux 2 base php; AL2023 php8.1 | No fix planned (Amazon) |
| SUSE SLE 15 SP7 (php7, php8), SLES 16.0, SLE 15 SP4 to SP6 LTSS, SLE 12 SP5 php74 (SUSE-SU-2026:4843-1, 4844-1, 4852-1, 4853-1, 4870-1, 24271-1); bci/php, bci/php-apache and bci/php-fpm 8.3.36 images | Fixed; SLES 16.1 and 16.2, openSUSE Leap 15.x and 16.x, SUSE Manager 4.x and the bci/php:8-micro image still affected |
| PHP 7.4, 8.0, 8.1 from php.net | No official release; PHP published source backports only |
| PHP 5.4 to 7.3 | End of life, no fix from PHP |
Check your own build.
# Debian / Ubuntu: is the fix in the installed package?
zgrep -E 'CVE-2026-10961[89]' /usr/share/doc/php*/changelog.Debian.gz
# RHEL / Fedora / Amazon Linux / Oracle Linux (package names vary: php-common, php8.4-common, ...)
rpm -qa 'php*common*' | xargs -n1 rpm -q --changelog | grep -E 'CVE-2026-10961[89]'
# Alpine / Wolfi / Chainguard: compare with the fixed versions above
apk info -v | grep -E '^php'
# Anything else: the version, then your vendor's advisory
php -v
An empty result isn't proof you're vulnerable: some changelogs cite only the advisory ID (DSA, USN, RHSA). If in doubt, compare your package version with your vendor's advisory.
Does this PHP take network input? PHP that serves web requests (mod_php, PHP-FPM, php-cgi, FrankenPHP, LiteSpeed) is in scope. PHP used only from the command line on local data (build images, local cron jobs) has no request-body route. In our reading of the code, a long-running PHP worker that processes data from the network should still be treated as in scope.
ss -ltnp | grep -E 'php-fpm|apache2|httpd|frankenphp|lsphp'
What doesn't protect you
Each of these lowers risk while you patch. None makes a server safe, and PHP's advisory says the same.
| Workaround | What it covers | Why it isn't enough |
|---|---|---|
session.upload_progress.enabled=0 |
The confirmed upload-progress route of CVE-2026-109619; fully covers CVE-2026-115560 until PHP's next release | PHP: it "blocks the confirmed session paths but not other variants". The other routes, and CVE-2026-109618, don't need it |
memory_limit=-1 |
The memory-limit trigger of CVE-2026-109618 | PHP: "an underlying allocation failure can still reach the vulnerable path"; it also removes your protection against one request using all memory |
fatal_error_backtraces=0 (8.5) |
One confirmed producer on PHP 8.5 | Covers that path only |
pm.max_requests=1 |
Each FPM worker handles one request, which breaks the confirmed cross-request sequence | PHP: recycling lowers success rates but doesn't remove the condition |
| Running PHP-FPM instead of mod_php | Some startup routes | PHP confirms CVE-2026-109619 code execution on FPM |
Lower post_max_size, input limits, WAF rules |
Some request shapes | Requests without a declared length and other shapes get around them; a WAF must inspect full bodies and field names. AWS's managed PHP rule (PHP2Shell_BODY) targets CVE-2026-109619 only |
Recovery and detection
- Patch (or move off an end-of-life branch), then restart every PHP worker.
- Verify the fix in the build with the commands above.
- If you must wait: apply the workarounds above in configuration that loads before request parsing (
php.ini, the FPM pool or server config, notini_set()or.user.ini), restart every worker, and isolate internet-facing PHP where you can. - Investigate from 17 October, not from the disclosure date, as Amazon advises: the first exploitation attempt came four days before the advisories.
- Look for:
- a web worker (for example
www-datarunning Apache) spawningshorbash, especially with outbound connections; PHP Fatal error: Allowed memory size of … bytes exhausted … in Unknown on line 0(a failure before any script ran);- worker crashes (
exit signal Segmentation fault) clustered with large POST requests; - requests with a single very long field name, or null bytes in a field with an empty name.
A note before rolling out widely: two reports, not yet confirmed by PHP's maintainers (php-src issues #24492 and #24493), say 8.5.12 and 8.4.27 can end a worker where the previous release raised a catchable error, and can lose sessions with reserved property names. Test first.
How Defendermate helps
- Verify exposure per build, not per version. Defendermate verifies, read-only and agentless, whether each finding is exploitable where it runs: whether the fix is actually in the build, and whether the conditions an attack needs are present. A scanner matching on the upstream PHP version can flag patched builds as vulnerable; the question that matters is which ones are exposed.
- Contain it while the patch is pending. Where you can't patch today, Defendermate delivers compensating controls as code, and orchestrates the real fix when it's ready.
Acknowledgments
Calif (LCFR), Wiz and OpenAI for the research; the PHP security team for the fix and the advisories; Datadog Security Labs, Sansec and JFrog for early analysis; Amazon Threat Intelligence for its early exploitation data; the Debian, Ubuntu, Red Hat, Alpine, Chainguard, Amazon and SUSE security teams.
References
- PHP security advisory (21 October 2026): https://www.php.net/archive/2026.php
- GHSA-w8hw-w9fx-j79w (CVE-2026-109618): https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w
- GHSA-6wmf-4rv5-p3rp (CVE-2026-109619): https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp
- Fix commits: https://github.com/php/php-src/commit/01a40e89fb · …/3c832b523e · …/506e87fa7d · …/31c0ea7d7f
- Calif: https://calif.io/php2shell · Wiz: https://www.wiz.io/blog/php2shell-php-rce · Datadog: https://securitylabs.datadoghq.com/articles/php2shell-critical-vulnerabilities-in-php/
- Amazon Threat Intelligence: https://aws.amazon.com/blogs/security/amazon-threat-intelligence-identifies-php2shell-exploitation-prior-to-public-disclosure-in-madpot/
- Cloudflare: https://blog.cloudflare.com/php-vulnerabilities-waf-protection
- Debian: https://security-tracker.debian.org/tracker/CVE-2026-109618 · Ubuntu USN-8948-1: https://ubuntu.com/security/notices/USN-8948-1 · Red Hat RHSB-2026-013: https://access.redhat.com/security/vulnerabilities/RHSB-2026-013
- CVE records: https://www.cve.org/CVERecord?id=CVE-2026-109618 · https://www.cve.org/CVERecord?id=CVE-2026-109619
Updates
- 21 October 2026: first published.
- 21 October 2026: scanner wording scoped to tools that read the upstream PHP version; distribution-aware scanners that read a distro's own advisories, such as Grype and Trivy for Chainguard and Wolfi, report these builds correctly.
- 22 October 2026: refreshed against our sources. Red Hat's bulletin now lists RHEL 7 as affected by CVE-2026-109619 in a default configuration; fixes added for Oracle Linux 8 and 9, AlmaLinux 8 to 10, Alpine v3.22 and v3.23, and more SUSE products; Amazon's per-CVE pages now match its advisories; NVD added a CVSS 3.1 score of 9.8. RHEL 9 php:8.4 still had no fix, and neither CVE was in CISA's KEV catalog.
- 22 October 2026: we've asked Red Hat Product Security to bring its VEX file for CVE-2026-109619 in line with its bulletin on RHEL 7, and whether RHEL 7 will get a fix. We'll update this page with their answer.
- 25 October 2026: refreshed against our sources. Amazon reworded its report from "now being broadly exploited in the wild" to "now seeing broad exploitation attempts in the wild"; we quoted the first wording and have corrected the overview and timeline. PHP disclosed a related bug, CVE-2026-115560, that the current releases don't fix; added under How it works and What to do now. Red Hat shipped a RHEL 7 fix for CVE-2026-109619 under Extended Life Cycle Support and its VEX now matches its bulletin, which answers the question we raised with Red Hat on 22 October. Added Debian forky and sid, Alpine v3.21 and SUSE's container images. RHEL 9 php:8.4 still has no fix, and neither CVE is in CISA's KEV catalog as of its 23 October update.