Nuno
Nuno
All posts

PHP2Shell: What to Check on Your PHP Servers This Week

Two critical PHP flaws were fixed on October 21, 2026. Which setups are most at risk, how to tell if your servers are patched when your distro backports fixes, and what to do if you can't patch today.
Vander Nunes
October 25, 2026
XInstagramYouTubeLinkedIn
Back of a server with fan modules and cables in a gradient circle, next to the post title

On October 21, 2026, PHP shipped 8.5.12, 8.4.27, 8.3.36 and 8.2.35 to fix two flaws that let someone run code on your server without logging in. They're tracked as CVE-2026-109618 and CVE-2026-109619, both rated 9.2, and people have started calling them PHP2Shell.

The flaws live in PHP itself, not in WordPress, Drupal, Magento or Laravel. So it doesn't matter how well your CMS is kept up to date. If the PHP underneath is an old build, the site is exposed.

Here's what I would check this week, in order.

Who is most at risk

Every PHP install that serves web requests is in scope: Apache with mod_php, PHP-FPM, php-cgi, FrankenPHP and LiteSpeed.

They are not equally easy to attack, though. According to Rapid7's analysis, Apache with mod_php is the highest risk, because the first bug can be reached before your application code even runs. On PHP-FPM, a worker that fails at startup simply dies, which blocks that exact path. FPM is still affected, just through harder routes.

As of October 25, public proof-of-concept code exists, but the researchers who tested it found each one only works on a narrow mix of OS, PHP version and web server. Exploit attempts have been reported. That gap usually closes fast, so I wouldn't treat "hard to exploit" as a reason to wait.

PHP 8.1 and older no longer get routine fixes. If you're still on 7.4, 8.0 or 8.1, CISA's advice is blunt: take internet-facing systems offline until you can update.

Step 1: Find every PHP you run

The PHP you think you run and the PHP actually serving requests are often different. I'd look in four places:

  • Web servers and VMs you manage directly.
  • Container images. A base image built in March still has March's PHP, even if the host is patched.
  • Managed hosting and control panels (cPanel, Plesk). Many hosts patched on the day, some didn't.
  • Things that embed PHP without saying so: old admin tools, monitoring dashboards, a forgotten WordPress on a marketing subdomain.

On a Linux server, these tell you what's there and which mode it runs in:

Shell
php -vapachectl -M 2>/dev/null | grep -i php     # mod_php loaded?systemctl list-units --type=service | grep -i fpm

Step 2: Check if it's really patched

This is where most people get it wrong. Debian, Ubuntu, Red Hat and the other big distributions got the fix early and backported it. A backported package can still say "8.2.28" in php -v while being fully fixed.

So don't judge by the version number alone. Check the package changelog for the two CVE numbers:

Shell
# Debian / Ubuntuapt changelog php8.2 2>/dev/null | grep -E "CVE-2026-10961[89]"# RHEL / Rocky / Almarpm -q --changelog php | grep -E "CVE-2026-10961[89]"

If you build PHP from source or use official Docker images, the version number does matter: you need 8.2.35, 8.3.36, 8.4.27 or 8.5.12 or later.

After updating, restart every PHP process. An updated package with old workers still running is still vulnerable. For FPM that means restarting the FPM service, for mod_php restarting Apache.

Step 3: If you can't patch today

Sometimes there's a frozen release, a vendor appliance or an old app that breaks on a new minor version. Rapid7 lists interim steps that reduce exposure. They are not a fix, and they all need to be set at the server or FPM pool level, where the application can't override them:

  • session.upload_progress.enabled=0, then restart workers. Setting it with ini_set() or .user.ini is too late.
  • On PHP 8.5, fatal_error_backtraces=0.
  • Cap request sizes at the front: keep post_max_size small (8M, or 32M if you need uploads), and limit multipart parts and headers at the load balancer or WAF. If the app never takes uploads, block multipart requests entirely.
  • A web application firewall in front helps while you patch.

One thing not to do: don't lean on container memory limits or RLIMIT_AS as a guard. When the kernel enforces them, it can kill the whole PHP master process, or trigger the very allocation failure the first bug needs.

Step 4: Look for signs of trouble

CISA's guidance is to watch for PHP worker processes doing things they never should, like starting a shell or downloading tools. On most servers that's a short list to check:

Shell
ps -ef --forest | grep -A3 -E "php-fpm|apache2|httpd" | grep -E "sh -c|bash|curl|wget"

Also look at outbound connections from the web tier to addresses you don't recognize, and new files in web roots and /tmp. Quiet logs don't prove you're fine, but a PHP worker running wget is a clear sign something is wrong.

There's already a third one

On October 23, the PHP project published an informational advisory on CVE-2026-115560, which the October 21 releases do not fix. It covers a narrow case: an app that changes session.serialize_handler from php_binary or php_serialize to php at runtime with ini_set(). Until the next bugfix release, the PHP project recommends session.upload_progress.enabled=0, the same switch as above. The full advisory will come with the next release.

What makes a week like this easy

In my experience, the teams that get through a week like this in an hour have two things: a list of every place PHP runs, and a way to roll a new package or image out to all of them at once. The teams without them spend days finding servers. If this week was painful, build that inventory and a repeatable patch path now, before the next one.

Checklist

  1. List every server, image and hosted site that runs PHP.
  2. Confirm mod_php vs FPM on each one. Do mod_php first.
  3. Update, then check the changelog for both CVE numbers. Restart every worker.
  4. Anything on 8.1 or older that faces the internet: take it offline or put it behind strict request limits until it's upgraded.
  5. Set session.upload_progress.enabled=0 at server level until CVE-2026-115560 is fixed.
  6. Check for PHP workers spawning shells or making odd outbound connections.

If you'd like a second pair of eyes on a PHP fleet, or help moving off an unsupported version, get in touch.