TL;DR
Update to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35, or to your distribution's patched package, then restart every PHP worker. The two bugs (CVE-2026-109618 and CVE-2026-109619, nicknamed PHP2Shell) are each rated CVSS v4.0 9.2 and can give an unauthenticated attacker code execution as the web server user, before your application runs.
Don't trust the upgrade command. Check the installed version. On release day the Ondřej PPA used by Laravel Forge still served 8.3.35, which is notfixed. Until you're patched, set session.upload_progress.enabled=0 and lower post_max_size. These reduce risk but don't remove it.
What happened
The PHP security team gave advance notice on 20 October and published the releases on 21 October 2026, a little ahead of the announced 14:00 UTC slot. The php.net announcement says every PHP installation that serves web requests is at risk, including PHP-FPM, Apache mod_php, php-cgi, FrankenPHP and LiteSpeed. It rates the risk highest for mod_php, where a demonstrated exploit works before any application code runs. php.net security advisory
The CVE IDs leaked ahead of the planned disclosure, and the security press quickly settled on the name PHP2Shell, which is also the name of a public exploit tool that chains the two bugs. Researchers have demonstrated unauthenticated RCE against stock WordPress, Drupal, Joomla and Magento installs, because the flaw sits under all of them.
Which PHP versions are affected, and which are fixed?
| Branch | Vulnerable | Fixed upstream | Notes |
|---|---|---|---|
| PHP 8.5 | below 8.5.12 | 8.5.12 | Extra RCE path via fatal_error_backtraces |
| PHP 8.4 | below 8.4.27 | 8.4.27 | |
| PHP 8.3 | below 8.3.36 | 8.3.36 | 8.3.35 is not fixed |
| PHP 8.2 | below 8.2.35 | 8.2.35 | End of life 31 December 2026 |
| PHP 8.1, 8.0, 7.4 | Assume yes | No release | Source backports only; see below |
Distribution packages carry their own version strings. Ubuntu's security notice USN-8948-1 fixes 24.04's PHP as 8.3.6-0ubuntu0.24.04.13 and 22.04's PHP 8.1 as 8.1.2-1ubuntu2.28. Those are patched even though the upstream number looks old. For distro PHP, compare the package version with your vendor's advisory, not with “8.3.36”. Ubuntu USN-8948-1
The two bugs in plain English
CVE-2026-109618: RCE via out-of-memory corruption
When PHP runs out of memory it jumps straight out of the request. If that happens while a request is only partly set up, for example while parsing a crafted multipart upload, the clean-up code then treats half-initialised memory as valid. An attacker can steer that into code execution. Requests without a usable content length, parts with unlimited headers and piles of empty file fields can all trigger it. GHSA-w8hw-w9fx-j79w
CVE-2026-109619: RCE via stale global state
PHP workers are reused across requests. After a fatal error, some state a worker keeps between requests can still point at memory the previous request freed. The next request on that worker can touch it before normal initialisation resets it, which is a classic use-after-free. The confirmed paths include session upload progress, which is on by default and needs no session_start(), and on PHP 8.5 the fatal error backtrace feature. GHSA-6wmf-4rv5-p3rp
Who is at risk: mod_php, PHP-FPM, LSAPI or FrankenPHP?
| SAPI | CVE-2026-109618 (OOM) | CVE-2026-109619 (stale state) |
|---|---|---|
| Apache mod_php | Confirmed RCE | Confirmed RCE |
| PHP-FPM | Likely (source analysis, no full exploit shown) | Confirmed via session upload progress |
| FrankenPHP | Likely | No default early path found; not immune |
| LiteSpeed LSAPI | Likely | Conditional |
Most Laravel, Symfony and modern WordPress hosting runs PHP-FPM behind nginx, so “we don't use mod_php” isn't a reason to wait.
How to check your PHP version properly
php -v only shows the command-line binary. Your sites are served by PHP-FPM or the Apache module, which can be a different package or even a different version. Check what serves traffic, and check the package version:
# The CLI and the web SAPI can be different builds: check both
php -v
php-fpm8.3 -v # adjust to your version: php-fpm8.2, php-fpm8.4 ...
# The package version is what matters (distros backport fixes)
dpkg -l 'php*' | awk '/^ii/{print $2, $3}' # Debian / Ubuntu
rpm -qa 'php*' | sort # RHEL / Alma / RockyOn WordPress, Tools → Site Health → Info → Servershows the PHP version the site actually runs on. If you're on cPanel, check every ea-php version in use, not just the default. Not technical? Our plain-English guide for WordPress site owners explains what to ask your host.
How to update PHP
Ubuntu and Debian with Ondřej Surý's PPA
sudo apt-get update
apt-cache policy php8.3-fpm # is the candidate 8.3.36 (or your distro's fixed build)?
sudo apt-get install --only-upgrade 'php8.3*'
sudo systemctl restart php8.3-fpm # restart, not reload: every worker must be replaced
# Anything still running the old, deleted PHP binary?
sudo grep -lE ' /(usr|lib|opt).*\(deleted\)$' /proc/[0-9]*/mapsThe catch on release day: the Launchpad PPA (ppa:ondrej/php) still listed 8.5.11, 8.4.26 and 8.3.35 hours after the release, while Ondřej's separate packages.sury.org repository had fixed amd64 builds sooner. Ondřej Surý has confirmed the fix is coming to every PHP version he ships. If apt-cache policydoesn't show the fixed version yet, you're not patched. Apply the mitigations below and check again. ma.ttias.be patch-status tracker
Laravel Forge
Forge provisions PHP from the same Ondřej PPA, so neither Forge's PHP management nor an SSH session can install 8.3.36 before the PPA publishes it. That's exactly what we hit on a client server today. We installed the newest build the PPA offered, confirmed it was still 8.3.35, and added session.upload_progress.enabled=0 as a conf.ddrop-in. We then restarted PHP-FPM and checked every site on the box. The job isn't finished until php-fpm8.3 -vreads 8.3.36. If you're weighing Forge against managed platforms that patch the runtime for you, our Laravel Cloud vs Forge comparison covers that trade-off.
cPanel / WHM and Plesk
cPanel ships PHP as EasyApache 4 ea-php packages, and CloudLinux as alt-php, so the fix arrives when those vendors publish rebuilt packages. Run the system update (or WHM → EasyApache 4) and confirm each /opt/cpanel/ea-phpXX/root/usr/bin/php -v. Plesk has said every PHP version it ships is affected and is rebuilding them. Check Tools & Settings → Updates and plesk bin php_handler --list.
Managed and shared hosting
You can't patch PHP yourself here. Ask your host for the exact package version and the time it was deployed, in writing. A .user.ini or ini_set()change doesn't apply the mitigations, because they have to take effect before the request is parsed.
What to do if you can't update yet
php.net is explicit that these measures “do not make an installation safe”. They block the confirmed paths only. Apply them in php.ini, a conf.d file or the FPM pool, then restart every worker:
; /etc/php/8.3/fpm/conf.d/99-php2shell.ini (and apache2/conf.d for mod_php)
; Interim only: reduces exposure, does not fix CVE-2026-109618/109619
session.upload_progress.enabled = 0
post_max_size = 8M ; 32M if the app needs uploads
upload_max_filesize = 6M ; keep below post_max_size
; PHP 8.5 only:
; fatal_error_backtraces = 0- Cap request body size, field count, multipart parts and header count at nginx, Apache or your proxy, including requests with no
Content-Length. - Block
multipart/form-dataentirely on apps that never take uploads. - For CVE-2026-109618, php.net's primary config workaround is
memory_limit=-1enforced withphp_admin_value. It's still incomplete, and you need a container or cgroup memory limit to stay available. Never useRLIMIT_AS/RLIMIT_DATA, which trigger the bug. - Remove deprecated or invalid per-request INI settings that emit diagnostics, and consider
pm.max_requests=1if you can afford the performance cost. - Watch for multipart requests followed by memory-limit errors, bursts of HTTP 500s, oversized
PHPSESSIDcookies and unexplained worker restarts.
If a high-risk site can't be patched or mitigated quickly, take it offline at the web server or proxy until it can.
Still on PHP 7.4, 8.0 or 8.1?
The PHP project no longer releases these branches. PHP 7.4 has been end of life since November 2022. Given the severity, the security team did publish minimal source backports for 7.4, 8.0 and 8.1, but they only help you if you build PHP from source. For everyone else:
- Distro PHP (Ubuntu 22.04's PHP 8.1, Debian, RHEL): your vendor may ship a backport. Ubuntu already has, in
8.1.2-1ubuntu2.28. - PPA or vendor builds: check whether the provider rebuilds old branches. Otherwise ask an extended-support (LTS) vendor.
- Plan the upgrade. Researchers say the vulnerable code dates back to PHP 5.4, so “old” doesn't mean “unaffected”. Move to 8.3 or 8.4, not 8.2, which itself ends on 31 December 2026.
Frequently asked questions
- Is PHP2Shell being exploited in the wild?
- Treat it as exploited. Cloudflare reported early attack activity against PHP sites on the morning of 21 October 2026, before the fixed releases were out, and Patchstack said hosting partners reported incidents the same morning. Proof-of-concept code is public, though some of what circulates is unverified and may itself be malicious.
- Does updating WordPress, Laravel or my plugins fix PHP2Shell?
- No. Both bugs are in the PHP interpreter and are reachable before your application code runs, so a clean, fully updated WordPress, Magento or Laravel site is still exposed on a vulnerable PHP build. WordPress maintenance mode doesn't help either. Only the PHP package on the server, or your host's update, fixes it.
- Does a WAF or Cloudflare protect me from PHP2Shell?
- Partly. Cloudflare deployed WAF rules for known exploit vectors, but they only cover traffic that actually passes through Cloudflare, and new variants can get past a signature. A WAF buys time. It doesn't replace the update.
- Does 'apt upgrade' fix PHP2Shell?
- Only if your package source has published the fixed build. On 21 October the ppa:ondrej/php archive used by Laravel Forge still served 8.3.35, which does not contain the fix, so apt upgrade reported success without patching anything. Always confirm the installed package version afterwards and restart PHP-FPM or Apache.
- Should I keep session.upload_progress disabled after patching?
- Yes, if your application doesn't show upload progress bars from PHP's session upload progress feature. The advisory for CVE-2026-109619 suggests leaving it off even after patching when you don't need it, and most modern apps don't.
Primary sources
- php.net: security advisory and the 8.5.12, 8.4.27, 8.3.36 and 8.2.35 release notes
- GHSA-w8hw-w9fx-j79w: RCE via OOM corruption (CVE-2026-109618)
- GHSA-6wmf-4rv5-p3rp: RCE via stale global state (CVE-2026-109619)
- Ubuntu USN-8948-1: fixed package versions
- Tenable: PHP2Shell FAQ (exploitation and PoC status)
Service
Software Rescue & Security
Emergency patching, compromise checks and ongoing maintenance for PHP, Laravel and WordPress estates.
Guide
Laravel Cloud vs Forge vs a VPS
Who patches the runtime, and what that costs you on a day like this one.
UK edition
PHP2Shell: a UK patch plan
Cyber Essentials' 14-day rule, NCSC guidance and UK GDPR breach reporting.










































