Fix it: patch PHP, restart the workers, prove it
Fixed releases are PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Everything below is a route to one of those, or to a vendor backport that contains the same fix.
Two rules that decide whether this works. One: a package upgrade does not fix a running process — restart Apache, PHP-FPM and any container. Two: the command-line PHP is not the web PHP. Verify through the SAPI that serves traffic.
1. Find every PHP on the box first
Most “we patched it” failures are a second runtime nobody remembered: a control-panel branch pinned per domain, an old container, or a vendor appliance.
# what is actually serving
ps -eo pid,user,lstart,args | grep -Ei '[p]hp-fpm|[a]pache2|[h]ttpd|[l]sphp|[f]rankenphp'
# installed versions
php -v; ls -1 /etc/php/ 2>/dev/null
dpkg -l 'php*' | awk '/^ii/{print $2, $3}' # Debian/Ubuntu
rpm -qa 'php*' 'ea-php*' 'alt-php*' | sort # RHEL family, cPanel, CloudLinux
2. Patch, by platform
Ubuntu and Debian
sudo apt update
sudo apt install --only-upgrade 'php8.*' 'libapache2-mod-php8.*'
sudo systemctl restart php8.3-fpm apache2
Fixed package versions verified 22 Oct 2026: Ubuntu 24.04 8.3.6-0ubuntu0.24.04.13, Ubuntu 22.04 8.1.2-1ubuntu2.28, Debian 12 8.2.35-1~deb12u1, Debian 13 8.4.27-1~deb13u1. Ubuntu ESM also published fixes for 14.04 through 20.04.
RHEL, AlmaLinux, Rocky, CloudLinux
sudo dnf clean all
sudo dnf update 'php*'
sudo systemctl restart php-fpm httpd
RHEL 9's php:8.2 module moved to 8.2.35-1.module+el9.8.0+25111+a1450321. Red Hat backports without changing the upstream number, so trust dnf updateinfo list --security, not php -v.
cPanel / WHM
sudo /scripts/upcp --security
/usr/local/cpanel/bin/rebuild_phpconf --current
sudo /scripts/restartsrv_httpd
sudo /scripts/restartsrv_apache_php_fpm
for p in /opt/cpanel/ea-php*/root/usr/bin/php; do "$p" -v | head -1; done
EA4 25.91 shipped ea-php82/83/84/85 at the fixed versions, and backported the fix to ea-php74/80/81. cPanel's internal PHP (used by hooks) is a separate runtime, updated in cPanel & WHM 136.0.50 — do not assume one covers the other.
Plesk
sudo plesk installer update
sudo plesk bin php_handler --list
Plesk ships its own PHP builds and every one of them is affected. Check each handler individually; a server can have eight, with domains pinned to the oldest.
CloudLinux, DirectAdmin, HestiaCP, aaPanel
sudo yum update 'alt-php*' # CloudLinux Alt-PHP
cd /usr/local/directadmin/custombuild && ./build update && ./build php n # DirectAdmin
v-update-sys-php # HestiaCP
Docker and Kubernetes
docker pull php:8.3-fpm
docker image inspect php:8.3-fpm --format '{{index .RepoDigests 0}}'
docker compose up -d --force-recreate
kubectl rollout restart deployment/<name> -n <ns>
Pin by digest. A floating tag is whatever the registry had at pull time — which is how half a fleet ends up patched. Rebuild images that use FROM php:...; pulling a base image does nothing for a cached layer.
Windows / IIS
# replace the PHP tree IIS points at (check system.webServer/fastCgi), keep php.ini, then:
& $env:windir\system32\inetsrv\appcmd.exe recycle apppool /apppool.name:"DefaultAppPool"
PHP 8.1 and older
There is no upstream release. In order of preference: upgrade to 8.2+; apply a vendor backport (Ubuntu ESM, Debian ELTS, TuxCare ELS, cPanel ea-php, CloudLinux Alt-PHP); or build the PHP security team's minimal backport from the PHP-7.4-CVE-2026-109618-109619, PHP-8.0-… or PHP-8.1-… branches. Nothing exists for PHP 7.3 and below — isolate those hosts.
3. Verify it actually took effect
Four checks, per server. “Patched” without the last two is how people end up wrong.
| # | Proof | How |
|---|---|---|
| 1 | The serving SAPI reports a fixed version | Drop a temporary file with <?php echo PHP_VERSION, ' ', php_sapi_name(); in the web root, fetch it, delete it |
| 2 | The package is the fixed release | Full package version vs your vendor advisory — not just the first three numbers |
| 3 | Every worker restarted after the install | ps -eo pid,lstart,args | grep php-fpm — start time must be later than the package install |
| 4 | All installed branches fixed | Loop ea-php*, /opt/alt/php*, pools, containers |
Quick sanity check: if php -v says 8.3.36 but your site's headers or a phpinfo() page says 8.3.6, you have not patched the thing that matters. That specific mismatch is the single most common false “done” in this incident.
4. If you cannot patch today
PHP is explicit: there are no complete mitigations. These reduce exposure to known attack paths and buy time.
- Disable session upload progress —
session.upload_progress.enabled=0in the FPM pool orphp.ini, then restart every worker. Blocks the confirmed session paths only. - Block multipart uploads at the web server — every known trigger is
multipart/form-data, parsed before your code runs. It stops file uploads, so test a checkout or upload form first. - Remove PHP's memory ceiling —
php_admin_value[memory_limit] = -1in the pool, paired with a container memory cap. This trades code execution risk for a denial-of-service risk; do not do it casually on a shared box. - Do not use
RLIMIT_AS/RLIMIT_DATAor a panel'sRLimitMEM— the advisory warns these can cause the allocation failure the exploit needs. - Isolate — if none of the above is achievable, take the system off the internet. That is what the NSA and CERT-EU advised.
If the server was exposed before you patch, check for compromise first →
Need a second pair of eyes?
Multi-version panels, containers and staging copies are where this goes wrong. Verification evidence is the part that survives an audit.
Talk to someone