October 22, 2026
PHP2Shell: How Two Out-of-Memory and Stale-State Bugs Turned PHP Into an Unauthenticated RCE
A technical briefing on CVE-2026-109618 and CVE-2026-109619 for sysadmins, developers and security teams: what's broken, who is exposed…

By Joaquin López
8 min read
A technical briefing on CVE-2026-109618 and CVE-2026-109619 for sysadmins, developers and security teams: what's broken, who is exposed, how to detect it and how to patch
By Joaquín López
TL;DR
- What: two critical flaws in the PHP engine, together called "PHP2Shell". CVE-2026-109618 covers RCE via out-of-memory (OOM) corruption (GHSA-w8hw-w9fx-j79w). CVE-2026-109619 covers RCE via stale global state (GHSA-6wmf-4rv5-p3rp).
- Severity: CVSS v4.0 9.2 for both (
AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H). No authentication is needed. - Fixed in: PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. The ChangeLog entry reads: "Avoid state corruption via bailout".
- Exposure: per php.net, it affects "all PHP installations serving web requests, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed". The project rates the risk highest for mod_php.
- In the wild: Amazon saw an exploitation attempt against its MadPot honeypots on 17 October, four days before disclosure.
- No configuration-only fix exists. Disabling
session.upload_progressblocks one confirmed path but not the others. Patch, then restart every worker.
Timeline
All dates are 2026. Times are UTC as given by the sources.
- 17 Oct: Amazon Threat Intelligence logs a PHP2Shell exploitation attempt in MadPot from an anonymization-network IP.
- 20 Oct: The PHP security team pre-announces an emergency release for 21 Oct at 14:00 UTC. watchTowr says details had leaked before the coordinated disclosure, and it publicly confirms the issues are real and that it has reproduced them.
- 21 Oct, about 02:00–08:00 UTC: Amazon sees several proof-of-concept exploits and more attempts against MadPot from a range of anonymized infrastructure.
- 21 Oct, 14:00 UTC: The embargo lifts. php.net publishes its advisory and the releases, and the GitHub advisories and NVD entries go live.
- 21 Oct: CISA publishes "Critical Vulnerabilities in PHP Require Immediate Patching", NHS England publishes alert CC-4875, and AWS publishes its MadPot findings.
- 22 Oct: The php.net ChangeLog lists the four releases with the date 22 Oct. The release announcements are dated 21 Oct.
Technical analysis
Both bugs come from the same underlying problem. PHP aborts a request with a bailout, a longjmp() out of the current context. Sometimes it does this while its internal state is half-built, or while that state still points at memory owned by the request.
CVE-2026-109618: OOM corruption
PHP uses longjmp() to exit on out-of-memory errors. According to the advisory, in some contexts "request memory is temporarily reachable before it is fully initialized". If any allocation fails at that moment, even one unrelated to that memory, the request is left in an invalid state, and the shutdown procedure "may then read or branch on it".
The advisory lists several multipart parsing issues that let an attacker push a request into OOM while it still looks like it is within PHP's limits:
- A multipart request that has no usable declared content length can pass the initial
post_max_sizecheck. - A multipart part can carry an unlimited number of headers. These take far more memory inside PHP than they do on the wire.
- Empty file controls don't count toward
max_file_uploads, but they still create metadata arrays. Nested field names multiply that work.
Why mod_php is the worst case: Apache mod_php always runs request shutdown, even when request startup has failed. Body parsing during startup can therefore exhaust memory and leave invalid state behind before any application code runs. FPM handles this differently: it kills the child when startup fails. FPM is still considered susceptible after normal startup, but the advisory notes that "no complete FPM exploit has been demonstrated". From source analysis, FrankenPHP is "likely susceptible" and LSAPI is "likely but unvalidated".
The fix: the patch removes longjmp() for OOM. A "soft OOM" now fires at the next VM safe point, and a "hard OOM" calls _exit() once memory passes a second, higher threshold.
CVE-2026-109619: stale global state (use-after-free)
Workers keep global state (error, session, object and extension state) that can point into memory owned by a single request. A fatal error, including OOM or Maximum execution time exceeded, can skip the reset of that state. A late warning can also repopulate it after it has been cleared. The request heap is then freed while the global still points into it. If the next request on the same worker reads that pointer before normal initialization, you have a use-after-free.
Exploitation needs a producer and a consumer. The advisory confirms two early consumers:
- INI diagnostics before request initialization. A warning or deprecation raised by per-request INI settings is enough, such as
.htaccessorphp_valueunder mod_php, orPHP_VALUE/PHP_ADMIN_VALUEthat a frontend sends to FPM. The warning does not have to be shown or logged.error_reporting, @ anddisplay_errors=Offdo not protect you. - Session upload progress. This feature is enabled by default and does not require
session_start(). It can act as producer, consumer or both. The advisory reports this path as validated against both mod_php and FPM, though on FPM it "depends on a suitable application operation".
On PHP 8.5, enabling fatal_error_backtraces adds a confirmed producer. The advisory calls it "the strongest demonstrated case".
Impact, per the project: unauthenticated heap use-after-free, memory disclosure and RCE, all with the privileges of the web worker.
Affected versions and environments
(Medium doesn't render tables, so this is a list.)
- PHP 8.5: below 8.5.12 is vulnerable. Fixed in 8.5.12.
- PHP 8.4: below 8.4.27 is vulnerable. Fixed in 8.4.27.
- PHP 8.3: below 8.3.36 is vulnerable. Fixed in 8.3.36.
- PHP 8.2: below 8.2.35 is vulnerable. Fixed in 8.2.35. Security support ends 31 Dec 2026.
- PHP 8.1 and older: affected and end-of-life. The PHP security team released "minimal source-backports" for 7.4, 8.0 and 8.1 for people who build from source. Otherwise, use your vendor's backport or upgrade.
- SAPIs (from php.net and the advisories): mod_php carries the highest risk, with confirmed pre-application RCE. FPM has a confirmed path for the stale-state bug only. FrankenPHP, LSAPI and php-cgi are all listed by php.net as at risk.
Keep in mind that PHP often ships inside other products: appliances, control panels and vendor images. If you don't know which PHP version a product runs, ask the supplier.
Exploitation in the wild
- Amazon (AWS Security Blog): saw a MadPot attempt on 17 Oct from a commercial anonymization network and says it is "unclear how the actor acquired exploit information". More attempts on 21 Oct had varied payloads, which suggests multiple actors. Amazon says it is "unclear if any of these attempts would have succeeded in real-world systems", and now describes PHP2Shell as "broadly exploited in the wild". Its advice is to start investigations from at least 17 October.
- watchTowr: reports active exploitation attempts against both CVEs, seen in its honeypot network.
- NHS England (CC-4875): says researchers "have demonstrated successful exploits… achieving remote code execution in products integrating PHP such as WordPress, Drupal, and Joomla". NHS England assesses future exploitation as "highly likely".
- CISA (21 Oct): said it had not observed exploitation at publication time. It recommends taking unpatchable or EOL systems offline.
AWS published these IPs, with the caveat that they are shared anonymization infrastructure and should be investigated, not blocked: 103.216.220.92 (17 Oct), 31.223.184.166, 37.19.200.5, 134.209.159.64, 103.114.163.188 and 95.217.98.37 (all 21 Oct).
Detection
1. Find every PHP runtime. The CLI version can differ from the version FPM or Apache actually loads, so check each one:
php -v # CLI
php-fpm -v # binary name varies, e.g. php-fpm8.3
php -i | grep -E 'session.upload_progress|memory_limit|fatal_error_backtraces'
curl -sI https://your-site.example | grep -i x-powered-by # only if expose_php=On
docker run --rm <your-image> php -v # per container imagephp -v # CLI
php-fpm -v # binary name varies, e.g. php-fpm8.3
php -i | grep -E 'session.upload_progress|memory_limit|fatal_error_backtraces'
curl -sI https://your-site.example | grep -i x-powered-by # only if expose_php=On
docker run --rm <your-image> php -v # per container imageFor the web SAPI, phpinfo() or PHP_VERSION served from a restricted, temporary page is the authoritative check. Remove the page afterwards.
2. Look for the request pattern. AWS recommends looking for multipart POSTs that contain PHP_SESSION_UPLOAD_PROGRESS. That string sits in the request body, so ordinary access logs won't show it. You need WAF, reverse-proxy or body logs. The field name is configurable (session.upload_progress.name), so check yours.
grep -rl 'PHP_SESSION_UPLOAD_PROGRESS' /var/log/waf/ # adapt to your body/WAF log locationgrep -rl 'PHP_SESSION_UPLOAD_PROGRESS' /var/log/waf/ # adapt to your body/WAF log location3. Check the PHP and web-server error logs for fatal, memory and timeout errors, for example on unauthenticated upload endpoints:
grep -E 'Allowed memory size of [0-9]+ bytes exhausted|Maximum execution time|PHP Fatal error' \
/var/log/php*-fpm.log /var/log/apache2/error.loggrep -E 'Allowed memory size of [0-9]+ bytes exhausted|Maximum execution time|PHP Fatal error' \
/var/log/php*-fpm.log /var/log/apache2/error.logThe advisory also flags repeated warnings or deprecations before scripts run, and diagnostics during extension cleanup. It warns that "absence of an error in logs is not proof of safety".
4. Hunt for post-exploitation activity (CISA and AWS): PHP workers that spawn shells or download tools, and unexpected file changes since 17 Oct.
ps -eo pid,ppid,user,cmd --forest | grep -A3 -E 'php-fpm|apache2|httpd'
find /var/www -type f -name '*.php' -newermt '2026-10-17' -lsps -eo pid,ppid,user,cmd --forest | grep -A3 -E 'php-fpm|apache2|httpd'
find /var/www -type f -name '*.php' -newermt '2026-10-17' -lsMitigation and patching
- Patch to 8.5.12, 8.4.27, 8.3.36 or 8.2.35, or to your distro or LTS vendor's fixed package. php.net says distributions got the patches in advance. Restart every PHP worker afterwards.
- Containers: rebuilding on a fresh base image, redeploying and confirming with
php -vinside the running image is the only way to be sure. A patched host means nothing to a container. (The CVE has no opinion on how "immutable" your infrastructure is.) - Hosting and remirepo: on 21 Oct, php.net said rpms.remirepo.net "will not have updates today" and urged users to switch to distribution packages or build from source.
- If you can't patch right away (these reduce exposure but are not fixes):Set
session.upload_progress.enabled=0inphp.ini, the FPM pool or server config. Do not rely onini_set()or.user.ini.On PHP 8.5, setfatal_error_backtraces=0.php.net suggests enforcingmemory_limit=-1administratively for CVE-2026-109618. Be aware this trades memory safety for availability. Pair it with a container or cgroup limit, and do not useRLIMIT_AS/RLIMIT_DATA, because they trigger the vulnerable path.Keeppost_max_sizelow (php.net suggests 8M without uploads and 32M with them). Limit decoded body size, part count, header count and nesting at the proxy, including requests without aContent-Length. If you don't use multipart, block it at the frontend.Remove invalid or deprecated per-request INI settings that emit diagnostics. - General hygiene (these don't mitigate PHP2Shell, but help in general):
expose_php=Off,display_errors=Off,log_errors=On.
On lifecycle: PHP 8.1 is already EOL, and 8.2 loses security support on 31 Dec 2026. If this incident is how you find out you're on 8.1, there's your Q1 project.
The ISO/IEC 27001:2022 angle
Incidents like this test whether your ISMS controls actually work:
- A.8.8 Management of technical vulnerabilities: you need intake from sources like php.net, CISA and national CERTs, exposure assessment, and a defined reaction time. As AWS put it, for critical internet-facing flaws, "measure patch and mitigation timelines in hours". A 30-day SLA was written for a different threat landscape.
- A.5.9 Inventory of information and other associated assets: without a list of where PHP runs and which SAPI each system uses, A.8.8 is guesswork.
- A.5.7 Threat intelligence: honeypot telemetry showed exploitation before disclosure. Feed sources like that into your triage.
- A.8.15 Logging / A.8.16 Monitoring activities: if your logs can't see request bodies or worker process trees, you can't answer the question "were we hit on 17 October?".
- A.5.19–A.5.22 Supplier relationships and the ICT supply chain: ask hosting providers, SaaS vendors and appliance makers for written confirmation of patched versions and dates. Your supplier agreements should require them to notify you about vulnerabilities.
The same reasoning applies in TISAX-scoped environments, where supplier evidence carries just as much weight.
Conclusion
PHP2Shell is a reminder that the scariest bugs often live in error handling: the code path that runs when everything else has already gone wrong. Patch, restart workers, and hunt from 17 October onward. Treat "we disabled upload progress" as a temporary measure while you patch, not as the fix.
References
- PHP News Archive 2026 (security advisory and release notes): https://www.php.net/archive/2026.php
- PHP 8 ChangeLog: https://www.php.net/ChangeLog-8.php
- PHP Supported Versions: https://www.php.net/supported-versions.php
- GHSA-w8hw-w9fx-j79w (RCE via OOM corruption): https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w
- GHSA-6wmf-4rv5-p3rp (RCE via stale global state): https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp
- NVD CVE-2026-109618: https://nvd.nist.gov/vuln/detail/CVE-2026-109618
- NVD CVE-2026-109619: https://nvd.nist.gov/vuln/detail/CVE-2026-109619
- AWS Security Blog, Amazon Threat Intelligence and MadPot: https://aws.amazon.com/blogs/security/amazon-threat-intelligence-identifies-php2shell-exploitation-prior-to-public-disclosure-in-madpot/
- CISA alert (21 Oct 2026): https://www.cisa.gov/news-events/alerts/2026/10/21/critical-vulnerabilities-php-require-immediate-patching
- NHS England Digital, CC-4875: https://digital.nhs.uk/cyber-alerts/2026/cc-4875
- watchTowr, PHP2Shell Rapid Reaction: https://watchtowr.com/intelligence/php-remote-code-execution-php2shell/