Patching PHP2Shell on Ubuntu or Debian
The fixed versions are 8.5.12, 8.4.27, 8.3.36 and 8.2.35. PHP 8.1 and older get nothing — if you are still on one of those, this is the day you upgrade the major version. Every web SAPI is affected: PHP-FPM, Apache mod_php, php-cgi, FrankenPHP, LiteSpeed.
I patched two Ubuntu boxes yesterday afternoon, one running PHP-FPM 8.4 and one running mod_php 8.5. Here is what I did, including the one “shortcut” that cost me most of the time: the Ubuntu PPA most of us use did not have the packages yet.
“I’m using Cloudflare, so I’m fine”
No. Cloudflare pushed WAF rules on the morning of 21 October after seeing early attack traffic, and that is useful, but it only buys time not safety:
- The WAF only sees traffic that goes through Cloudflare. If your origin IP is reachable directly — DNS history, a non-proxied subdomain, mail on the same box, a firewall that still accepts 443 from anywhere — the attacker skips it.
- A WAF rule matches known exploit patterns. Variants and different trigger paths for the same core bug slip through until the rule is updated.
- CVE-2026-109619 is about state leaking between requests inside the same worker. A request that looks harmless on its own can be the setup for the next one, which is hard for a per-request filter to catch.
- Managed rulesets differ by plan, and a rule in log mode blocks nothing.
Treat the WAF as the reason you can finish your coffee first, not the reason to skip the patch.
Step 1: find out what you are actually running
The CLI and the web interpreter are separate binaries, and servers usually have previous inactive PHP versions installed. Run this first:
You are patching every PHP version that has a web SAPI, not just the one your main site uses. An unpatched 8.3 pool listening on a socket “nothing uses” is still exploitable if anything reaches it.
Step 2: the Sury PPA snag, and the fix
If you installed PHP on Ubuntu from ppa:ondrej/php, you probably saw this a couple of hours after the release:
Still 8.4.26. Meanwhile the fixed build was already sitting on packages.sury.org:
Ondřej Surý is merging the Launchpad PPA into packages.sury.org, which is now the canonical repo for Ubuntu as well as Debian. New builds land there first and the PPA lags — on a day like this, by hours. The Launchpad PPA also still signs with an RSA-1024 key that newer apt warns about, so you want to move anyway.
The switch takes a minute. Replace noble with your own codename from lsb_release -sc:
The package naming is identical (php8.4-fpm, php8.4-mysql, etc.), so nothing else changes.
Step 3a: upgrading PHP-FPM
Upgrade every installed package of that version together — the extensions must match the interpreter or FPM will refuse to start. --force-confold keeps your pool and php.ini files untouched.
Use restart, not reload. A reload lets existing workers finish what they are doing, which means old-interpreter processes stay alive for a while. CVE-2026-109619 is specifically about state carried between requests in a worker, a restart kills those workers and spawns new ones.
Repeat for every other version with an FPM service (php8.3-fpm, php8.2-fpm, …).
Step 3b: upgrading Apache mod_php
The second box was Jammy with libapache2-mod-php8.5 and no FPM at all. Same repo switch, then include the Apache module in the upgrade and do a full Apache restart.
CLI-only installs (cron jobs, Composer, queue workers) pick up the new binary on the next invocation, but any long-running PHP daemon (queue workers under Supervisor, php -S, FrankenPHP, Swoole) has to be restarted by hand.
If the package is not there yet
On a distro or repo that is still behind (Remi for RHEL was explicitly flagged as not having builds on day one), do not leave FPM exposed while you wait. The PHP advisory lists interim mitigations; put them in the FPM pool, not php.ini, so applications cannot override them:
Then php-fpm8.4 -t && systemctl restart php8.4-fpm, for every pool and every version.
Step 4: verify both SAPIs
php -v only tells you about the CLI. Check the web side with a throwaway file, then delete it:
Both should print the fixed version for your branch — 8.4.27, 8.5.12, 8.3.36 or 8.2.35. If the CLI says one thing and the browser another, an older package is still installed somewhere then go back to step 1.
What about PHP versions before 8.2?
Update them to the latest PHP immediately. A huge deal of websites still use versions 7.4 or even older. If you are in this pool, take this opportunity to update your PHP version, preferably to the latest (8.5 as of writing this article).
There is nothing else you can do, but to update, otherwise eventually you will fall victim to the “PHP2Shell” attacks, which is far more devastating as updating your PHP version, which usually takes less than 20 minutes.