Back to Blog
php2shell: The Leaked PHP RCE Bugs and What to Patch Today
Two critical PHP bugs (CVE-2026-109618 and CVE-2026-109619) leaked before the patch. Here is how I check PHP version and SAPI, upgrade on Ubuntu, and what to do with old PHP 7.2 boxes that have no official fix.
Back
Engineering
Table of contents
Details of two critical PHP vulnerabilities started leaking on October 20, 2026, while the bugs were still under embargo. Researchers started calling it "php2shell". That evening the PHP security team announced a security release for the next day, and the fixes shipped on October 21 at 14:00 UTC, which is 21:00 WIB.
This is a bug in PHP itself, not in Laravel, WordPress, or any one framework. If a server runs PHP and answers web requests, it is in scope. A lot of us in Indonesia still run a mix of VPSes, shared hosting, cPanel boxes, and one or two old client servers nobody wants to touch. All of those count.
Quick Answer
Upgrade PHP to one of these versions, then restart every PHP worker:
- 8.5.12
- 8.4.27
- 8.3.36
- 8.2.35
PHP 8.1 and older get no official release. If you are on those, you need a distro or LTS vendor package, a source build with the backport, or a migration. Config changes below reduce exposure but PHP itself says they do not make an install safe.
What the two bugs are
Both are rated critical, CVSS v4.0 9.2, with no authentication and no user interaction required. That 9.2 is PHP's own rating. NVD now lists both CVEs too, and its own CVSS 3.1 score for each is 9.8.
- CVE-2026-109618 (GHSA-w8hw-w9fx-j79w), RCE via OOM corruption. When PHP runs out of memory at the wrong moment, request data can be left half initialized. Request cleanup then treats that data as valid. The advisory says complete RCE was validated over HTTP against Apache mod_php with default input and memory limits.
- CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp), RCE via stale global state. Some request-owned state survives after its memory is freed. A later request on the same worker can touch that stale state before normal initialization resets it. The advisory lists use-after-free, memory disclosure, and RCE as the confirmed impact.
Both advisories score attack complexity as high, and the exploits need the right worker and memory conditions. I would not read that as comfort. Amazon says its honeypots saw a php2shell exploit attempt on October 17, four days before disclosure, and now describes it as broadly exploited in the wild. Cloudflare also reported attack traffic against its customers before the release. Neither says how many of those attempts actually succeeded, but proof-of-concept code is already public, so I would assume scanning has reached your servers.
Who is most exposed
PHP's own advisory says every installation serving web requests is at risk: PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP, and LiteSpeed.
The risk is highest under mod_php. For the OOM bug, the attack can trigger during automatic request body parsing, before any of your application code runs. Your framework, middleware, and validation never get a say.
FPM is not off the hook. For the OOM bug, the advisory calls FPM susceptible from source analysis, though no complete FPM exploit was shown. For the stale-state bug, the session upload progress path was validated against both mod_php and FPM. FrankenPHP and LiteSpeed are described as likely or conditionally exposed. Patch them all.
Step 1: Check your version and SAPI
On the server:
bash
php -v
php -i | grep 'Server API'Careful: php -v and php -i show the CLI binary. Your web server may use a different PHP version or SAPI. To see what the web side actually runs, drop a temporary phpinfo() file, open it once, and delete it right away:
php
<?php phpinfo();Look at "PHP Version" and "Server API". "Apache 2.0 Handler" means mod_php. "FPM/FastCGI" means PHP-FPM. Do not leave that file on a public site.
It also helps to list what is installed and running:
bash
dpkg -l | grep -E '^ii\s+(php|libapache2-mod-php)'
systemctl list-units --type=service | grep -i php
apache2ctl -M 2>/dev/null | grep -i phpThe last command shows a php_module line if mod_php is loaded.
Step 2: Upgrade on Ubuntu
If you use Ondřej Surý's PPA
Most Laravel servers I see use ppa:ondrej/php. The PPA published 8.5.12, 8.4.27, 8.3.36, and 8.2.35 builds for Ubuntu 22.04 and 24.04 on release day. Swap 8.3 for your branch:
bash
sudo apt update
sudo apt install --only-upgrade 'php8.3-*'
php8.3 -vQuote the glob so your shell does not expand it against files in the current directory. If you have more than one PHP branch installed, upgrade each of them, including the ones you think nothing uses.
If you use Ubuntu's own packages
Ubuntu backports fixes without bumping the upstream version, so php -v will not say 8.3.36. Check the package version instead. USN-8948-1 lists the fixed builds, for example 8.3.6-0ubuntu0.24.04.13 on 24.04 and 8.1.2-1ubuntu2.28 on 22.04. A normal sudo apt update && sudo apt upgrade pulls them in.
bash
apt policy php8.3-fpm libapache2-mod-php8.3If you use Remi's repo on RHEL, AlmaLinux, or Rocky
PHP's advisory said on release day that rpms.remirepo.net would not have updates that day, and it urged users to switch to distribution packages or build from source. That may have changed since, so check before you rely on it, and do not assume dnf update fixed anything until the package changelog mentions both CVEs.
Shared hosting and panels
If you are on shared hosting or a managed panel, you probably cannot do this yourself. Open a ticket with your host and ask which PHP builds they are running and whether they include the fix for CVE-2026-109618 and CVE-2026-109619. Do not accept "we are on PHP 8.x" as an answer.
Step 3: Restart everything
New packages do nothing until the old processes are gone. Restart, do not just reload, so no old worker keeps serving requests.
bash
sudo systemctl restart php8.3-fpm
sudo systemctl restart apache2Then confirm. Run ps -o pid,lstart,cmd -C php-fpm8.3 and check the start times are after the upgrade, and reload your temporary phpinfo() page (then delete it again) to make sure the web side reports the new build.
If you use Docker, rebuild on a fixed base image tag and redeploy. Pulling the image is not enough if the running container is still the old one.
Step 4: Drop mod_php if you do not need it
If Apache loads modphp but your sites already run through FPM, or you can move them to FPM, turn modphp off. On Debian and Ubuntu:
bash
sudo a2dismod php8.3
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.3-fpm
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
sudo apache2ctl configtest && sudo systemctl restart apache2Test on staging first. The .htaccess files with php_value lines will break under FPM, and those need to move into the FPM pool config. That migration is worth doing anyway, but this is still not a substitute for upgrading.
If you cannot upgrade today
PHP lists these as measures that reduce exposure to specific attack paths. They are not a fix. Put them in php.ini, the FPM pool, or the server config, then restart every worker. ini_set() and FPM .user.ini do not apply early enough, so do not rely on them.
For the stale state bug (CVE-2026-109619):
ini
session.upload_progress.enabled = 0
; PHP 8.5 only
fatal_error_backtraces = 0The advisory says it might be prudent to leave upload progress off even after patching if you do not use it. Almost nobody does.
For the OOM bug (CVE-2026-109618), set the PHP memory limit to unlimited in a way the app cannot override, and lean on a container or cgroup limit instead. In an FPM pool:
ini
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M
php_admin_value[upload_max_filesize] = 6MUse post_max_size = 32M if you need file uploads, and keep upload_max_filesize below it. Check that no other pool, vhost, or app setting puts a finite memory_limit back.
Two warnings from the advisory that are easy to miss:
- Do not use
RLIMIT_ASorRLIMIT_DATAas the memory cap. Those make allocations fail, which is exactly the vulnerable path. - A cgroup limit that kills the whole container also kills the FPM master. A policy that kills only the affected worker is better.
The advisory also suggests enforcing request size limits at the web server or proxy, cleaning up invalid or deprecated INI settings, and fixing fatal errors and timeouts that attackers can reach. Hiding warnings with error_reporting, display_errors, or @ does not help.
Old PHP 7.2 boxes
This is the uncomfortable part. Every agency I know has at least one. PHP 7.2 has been end of life since 2020, and the PHP security team's minimal source backports only cover 7.4, 8.0, and 8.1. There is no official 7.2 patch.
Your options, roughly in the order I would try them:
- Check for a vendor package. Ubuntu Pro has a fixed
php7.2for Ubuntu 18.04 in USN-8948-2, and it is free for up to five machines. If the box runs 18.04 with stock PHP, this is the cheapest real fix. Commercial LTS vendors are another route. TuxCare, for example, has publishedalt-php72errata for both CVEs on EL8 and EL10, and says builds for other branches and platforms are still rolling out. Those packages install side by side under/opt/alt/, so you still have to point the site or FPM pool at them. Their changelog also lists behaviour changes: hittingmemory_limitnow kills the worker, and session upload progress is disabled. It is a paid product, I have not tested it, and the fix is TuxCare's own backport rather than an official PHP release. - Apply the mitigations above and restart. Treat it as buying time, not as fixed.
- Isolate it. Take it off the public internet, or put it behind a VPN or IP allowlist so only known users can reach it. If it only serves an internal admin panel, this is often doable in an afternoon.
- Be realistic about a WAF. Cloudflare has shipped managed php2shell rules that are on by default for every plan with the WAF, including Free, and ModSecurity can cap body size and block obviously bad multipart requests. That helps. But the bugs live inside PHP's request handling, and I would not assume a generic WAF rule catches every variant. It narrows the door. It does not close it.
- Plan the migration now. Community patches for 7.2 exist on GitHub, but they are unofficial, and I cannot vouch for how complete they are. If you build from them, test hard. The real answer is moving the app to 8.3 or 8.4. If the client keeps saying "next quarter", this is a good moment to send them the CVE numbers.
Watch for signs of exploitation
If an attacker gets code execution, the usual trace is the PHP worker starting programs it should never start. Watch for php-fpm, php-cgi, httpd, or apache2 spawning:
- shells like
shorbash - interpreters like
pythonorperl - network tools like
curl,wget, ornc
Command lines with /dev/tcp/, mkfifo, or fsockopen deserve a close look, and so do whoami, id, or uname -a run straight from the web server.
Florian Roth's free process-watcher does this on Linux with eBPF. It ships with a PHP observe config. It needs root (or CAP_BPF and CAP_PERFMON) and Linux 5.15 or newer with BTF, and sudo ./process-watcher doctor tells you whether your host qualifies. Start in observe mode. It only sees code that starts a process, so it is a detection layer, not protection.
In access logs, Amazon suggests looking for multipart POST requests that carry the PHP_SESSION_UPLOAD_PROGRESS field. Plenty of sites never use it, so a burst of those is worth a look. Default access logs do not record POST bodies, though, so a clean log is not an all clear.
How far back to look matters too. Since Amazon saw attempts from October 17, I would review an unpatched server from at least that date, not from the release day.
If you find something, isolate the server, keep the web and PHP logs, and look for new files in the web root, new cron jobs, and new users.
Do not go hunting for exploits
Proof-of-concept repos for these CVEs are already on GitHub. I have not reviewed any of them, and I would not run unvetted exploit code on any machine I care about. Fake exploit repos that drop malware on whoever runs them are a known trick after big disclosures.
I also have not found a public scanner I would trust for this. The honest check is the version and package check above. And never test anything against a server you do not own or have written permission to test.
My take
The patch is the fix. Everything else is a speed bump. What worries me is not the servers we deploy every week. It is the PHP we forgot about: the old client VPS, the panel that bundles its own PHP, the staging box with a public IP.
So today I would patch and restart, check the web SAPI and not just the CLI, kill mod_php where it is not needed, and make a list of every PHP 7.x and 8.1 box with a date next to each one. If a client server has no patch available, isolate it first and argue about the migration budget afterwards.
Sources
- PHP security advisory: Critical remote code execution vulnerabilities
- PHP news archive 2026 (includes the October 20 advance notice)
- GHSA-w8hw-w9fx-j79w: RCE via OOM corruption (CVE-2026-109618)
- GHSA-6wmf-4rv5-p3rp: RCE via stale global state (CVE-2026-109619)
- PHP 8.4.27 release announcement
- Ubuntu USN-8948-1: PHP vulnerabilities
- Ubuntu USN-8948-2: PHP vulnerabilities (older LTS releases)
- Ondřej Surý PPA packages
- NVD: CVE-2026-109618
- NVD: CVE-2026-109619
- Amazon Threat Intelligence: PHP2Shell exploitation prior to public disclosure
- Cloudflare: protections against php2shell
- Huntress: php2shell, Leaked Critical PHP Vulnerabilities
- TuxCare: php2shell patches for end of life PHP
- TuxCare errata CLSA-2026:1792622679: alt-php72 on EL8
- Neo23x0/process-watcher
Comments
No comments yet
Loading comments...