Skip to content
SecurityPHP2Shell affects most WordPress sites. Am I affected? →
presscomet
Security

PHP still shows as vulnerable after you updated it

You updated PHP but Site Health still shows the old, PHP2Shell-vulnerable version. Six common reasons — unrestarted workers, CLI vs web SAPI, Docker containers, the backport number trap and multiple PHP versions — and how to fix each.

By the Presscomet teamPublished 12 min read

On this page
  1. Why it still looks old
  2. Restart the workers
  3. CLI vs the web SAPI
  4. Docker: pull vs recreate
  5. The backport number trap
  6. Multiple PHP versions
  7. Confirm you're actually fixed

You updated PHP. So why is it still the old version?

You switched the PHP version, or ran the update command, or your host said it was done — and Tools › Site Health › Info › Server still shows the old, PHP2Shell-vulnerable number. This is one of the most common and most alarming moments in patching this flaw, because it looks like the fix failed. Usually it didn’t: the new PHP is installed, but something is keeping the old one in front of your visitors.

There are six usual culprits, and they’re all fixable in minutes once you know which one you’re looking at. In rough order of how often they bite:

#1 cause
Workers not restarted
#2 cause
Checked CLI, not web SAPI
#3 cause
Docker not recreated
Not a bug
Backport keeps old number
Also check
Multiple PHP versions
Read this value
Site Health › Server

One rule governs all six: the version that matters is the one serving web requests, and the only place that reliably reports it from inside WordPress is Site Health. Here’s what you’re reading — the PHP version and the PHP SAPI rows:

yoursite.com/wp-admin/site-health.php?tab=debug

Site Health

StatusInfo

Server ▴

Server architectureLinux 6.8.0 x86_64
Web servernginx/1.26.2
PHP version8.3.14 (Supports 64bit values)
PHP SAPIfpm-fcgi
PHP max input variables1000
PHP time limit30
PHP memory limit256M

Other panels: WordPress, Directories and Sizes, Drop-ins, Active Plugins, Database…

Tools › Site Health › Info › Server. The PHP SAPI tells you how PHP is run, which tells you what to restart. Illustration — your values will differ.

The SAPI value is the clue to everything below: fpm-fcgi means PHP-FPM, apache2handler means Apache mod_php, litespeed means LiteSpeed. That tells you which service has to restart. If you haven’t yet confirmed which PHP version is even the fixed one, keep the check-and-update-PHP guide open alongside this; here we assume you updated and are stuck on “it didn’t take”.

Cause 1: the workers never restarted

This is the big one. PHP doesn’t re-read itself on every request — for speed, the server loads PHP once into long-lived worker processes and keeps it there. Install a new build and those running workers still hold the old code in memory until the service restarts. The package manager says “done”; Site Health, truthfully, still shows the old version.

Restart the service that matches your SAPI. Pick the tab:

For fpm-fcgi. Restart the FPM service for your version (there may be more than one installed — restart the one serving the site):

Ubuntu / Debian / RHEL (adjust the version)
# See which php-fpm services exist and which are running$ systemctl list-units 'php*fpm*'# Restart the one that serves your site$ sudo systemctl restart php8.3-fpm# On RHEL/Alma/Rocky the service is usually just php-fpm$ sudo systemctl restart php-fpm

A graceful reload also works, but when you’re patching a critical flaw a full restart removes any doubt that old workers are gone.

After restarting, hard-reload Site Health

Reopen Tools › Site Health › Info › Server (Site Health caches some info for a few minutes, so give it a moment or reload). If the version changed, you’re done. If it didn’t, it’s one of the next five causes — not a failed restart.

Cause 2: you checked the command line, not the web PHP

A classic false alarm in the other direction: you run php -v over SSH, it shows a patched version, and you assume the site is safe — or it shows an old version and you panic. Both can be misleading, because php -v reports the command-line PHP (the CLI SAPI), which is frequently a different version from the one serving your pages.

A server commonly has several PHP builds installed at once. The CLI might be 8.1 while your site runs on 8.3 via FPM, or the reverse. WP-CLI also uses the CLI PHP, so wp --info reflects the command line too — not your visitors’ PHP.

Compare the CLI PHP with the web-facing PHP
# This is the CLI PHP — NOT necessarily what serves the site$ php -v$ wp --info# The FPM binary that actually serves requests (adjust the version)$ php-fpm8.3 -v# Which php packages are installed, and their exact builds (Debian/Ubuntu)$ dpkg -l | grep -E 'php[0-9.]+-(fpm|cgi)|libapache2-mod-php'# RHEL / AlmaLinux / Rocky$ rpm -q php php-fpm

The tie-breaker

When the command line and Site Health disagree, Site Health wins for security purposes, because it reports the PHP that answers web requests. If you want to double-check from the browser, a temporary phpinfo() page shows the serving version and its build date — just delete the file immediately afterward.

Cause 3: Docker image pulled, container not recreated

In a container setup, “update PHP” means moving to a fixed image tag — the official php images publish 8.5.12-*, 8.4.27-*, 8.3.36-* and 8.2.35-* (there are no maintained tags for 8.1 or older). But here’s the trap that catches everyone: pulling a new image doesn’t touch a running container. The container keeps running the old image until you recreate it.

Docker / Compose — recreate, don't just pull
# What is the RUNNING container actually on?$ docker exec <container> php -v# If you build your own image, pin a fixed tag (e.g. FROM php:8.4.27-fpm) then rebuild:$ docker compose build --pull# The step people forget — recreate the container from the new image:$ docker compose up -d --force-recreate# Plain docker: pull then recreate$ docker pull php:8.4.27-fpm

Two more gotchas. The official wordpress image is built on top of the php image, so it needs re-pulling or rebuilding too — updating only your own layer isn’t enough. And FrankenPHP users should move to v1.13.2 or later, which bundles the fixed PHP; again, the running process has to be recreated, not just the binary replaced on disk.

Cause 4 (not really a bug): the backport number trap

Sometimes the version genuinely didn’t change — and that’s fine. Linux distributions and several hosts fix security bugs by backporting the patch into their existing package without raising the upstream version number. So a site can be fully protected while Site Health still reads a number below the “fixed” one.

Concrete examples from the PHP2Shell rollout:

  • A site was reported protected while still showing PHP 8.4.26 — lower than the upstream fixed 8.4.27 — because its host applied a backport.
  • Ubuntu 24.04’s patched package still reports 8.3.6 (build 8.3.6-0ubuntu0.24.04.13, via USN-8948-1).
  • Plesk’s fixed 7.4/8.0/8.1 builds keep their old version numbers but carry an October 21, 2026 build date.

So a “low” number does not always mean unpatched. What you verify instead is the package revision and the CVEs, not the three-part version:

Verify the fix without trusting the version number
# Does the package changelog mention BOTH CVEs? (RHEL family)$ rpm -q --changelog php | grep -E 'CVE-2026-10961[89]'# Debian/Ubuntu: confirm the package revision matches the advisory$ dpkg -l | grep -E 'php[0-9.]+-fpm'# Check the installed build date against the advisory (adjust the version)$ php-fpm8.3 -v

On managed hosting, get it in writing

If you can’t inspect packages yourself, the version number alone can’t answer the question. Ask your host to confirm, in writing and with a date, that both CVE-2026-109618 and CVE-2026-109619 are fixed on your server and that PHP was restarted. “We’re on 8.4.26” is not an answer by itself; “8.4.26 with the backport applied on 21 Oct” is.

Cause 5: several PHP versions, and the site points at the wrong one

If the restart worked and it isn’t a backport, the update probably landed on a different PHP version or domain than the one serving your site. Multi-version setups make this easy to do:

  1. Step 1: Per-domain MultiPHP (cPanel)

    In MultiPHP Manager each domain can run a different branch (ea-php81, ea-php83…). Updating the server’s packages doesn’t move a domain that’s pinned to an old branch — change the domain’s version, or confirm the branch it’s on was itself patched.
  2. Step 2: The web server points at a specific socket

    An Nginx/Apache vhost often targets one FPM socket, e.g. php8.1-fpm.sock. If you installed and restarted php8.3-fpm but the vhost still proxies to the 8.1 socket, your site is still on 8.1. Repoint the vhost and reload the web server.
  3. Step 3: You restarted the wrong FPM service

    With several phpX.Y-fpm services installed, restarting php8.2-fpm does nothing for a site served by php8.3-fpm. Match the restart to the SAPI/version Site Health reports.

The quick way to untangle it: read the serving version in Site Health, find which socket or handler your vhost uses, and make sure the thing you updated and restarted is that exact one. Our guide to checking and updating PHP walks through installing versions side by side and repointing cleanly.

Confirm you’re actually fixed

Once Site Health shows the version you expect, sanity-check it. The checker below runs entirely in your browser — it takes the version, SAPI and hosting type you give it and tells you whether that combination still looks exposed, including the backport nuance. It can’t see your server, so it’s a guide, not a guarantee; your host’s or distro’s advisory is always the final word.

Interactive checker

Am I affected by PHP2Shell?

Runs in your browser · nothing is sent

  1. PHP version
  2. Server API
  3. Hosting
  4. Verdict

Find it in wp-admin under Tools › Site Health › Info › Server. Copy the whole number, e.g. 8.3.14.

Try:

Then run this short close-out:

  1. Step 1: Web-facing version matches a fix

    Site Health shows 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 or a vendor-backported build you’ve verified covers both CVEs.
  2. Step 2: You confirmed, not assumed, for backports

    If the number is lower because of a backport, you checked the changelog or got written confirmation that both CVEs are addressed.
  3. Step 3: Workers were restarted

    The version changed after a restart, not just after an install — proof the running workers use the patched code.
  4. Step 4: You checked exposure during the window

    If the site was online and unpatched between 17 and 21 October, run the “was I hacked?” checklist — a patch doesn’t remove anything already planted.

Tired of chasing PHP versions? Presscomet doesn't have one

Every one of the traps on this page — unrestarted workers, CLI-versus-web confusion, backport numbers, per-domain versions — exists because there’s a PHP interpreter in front of every request. Presscomet runs the WordPress admin, block editor, URLs and REST API on Node.js with a single SQLite file and no PHP runtime at all, so there’s no PHP version to track and the PHP-runtime class of bugs (PHP2Shell included) doesn’t apply. It’s not “unhackable”: Node.js, its npm dependencies, its own login and the host OS still get patched like anything else. It also doesn’t run PHP plugins (the common ones are built in) and doesn’t support WooCommerce.

If a stack with no PHP version to babysit sounds better than this, check your site against a migration — it only reads your public site and changes nothing on your server. For the patch-first path, keep our WordPress security guide and the full PHP2Shell guide handy. Either way, the finish line is the same: the web-facing PHP shows a fixed build, and you’ve proven it rather than hoped it.

Sources

Facts checked against these sources on October 24, 2026. Things change quickly; the vendor advisory always wins.

  1. [1]PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 security releases — PHP.net
  2. [2]PHP2Shell for WordPress: checking, restarting and the backport trap — Meow Apps
  3. [3]PHP2Shell: detection and verification guidance — Sophos
  4. [4]Two critical PHP flaws: find, mitigate and patch PHP2Shell — Qualys
  5. [5]PHP2Shell fixes by distro, control panel and PHP version — Digital Applied
  6. [6]USN-8948-1: PHP vulnerabilities (backported package versions) — Ubuntu
  7. [7]Debian security tracker: CVE-2026-109618 — Debian
  8. [8]Supported versions — PHP.net

Frequently asked questions

Why does Site Health still show the old PHP version after I updated?

Almost always because the PHP workers weren't restarted. PHP-FPM, Apache mod_php and LiteSpeed load PHP once and keep it resident, so a newly installed version isn't used until you restart the service. Other causes are checking the command-line PHP instead of the web one, a Docker container that was never recreated, or the version change being applied to a different PHP version or domain than the one serving your site.

Do I have to restart PHP-FPM after updating PHP?

Yes. Installing or upgrading the package puts the new files on disk, but the running FPM master and its worker processes keep the old code in memory until they restart. Run a restart such as systemctl restart php8.3-fpm (and your web server if it uses mod_php), then reload Site Health to confirm the new version is live.

Why does php -v show a different version than Site Health?

A server can have several PHP versions installed, each with its own SAPI. php -v reports the command-line PHP (the CLI SAPI, also what WP-CLI uses). Site Health reports the PHP that answers web requests for your site (fpm-fcgi, apache2handler or litespeed). For security that web-facing version is the one that matters, so trust Site Health over php -v.

My host shows PHP 8.4.26 — am I still vulnerable to PHP2Shell?

Not necessarily. Linux distributions and some hosts backport the security fix without bumping the version number, so a build reading 8.4.26 can be patched while 8.4.27 is the upstream fixed number. A site was reported protected while still showing 8.4.26. Don't judge by the number alone — confirm with your host or the distro advisory that both CVE-2026-109618 and CVE-2026-109619 are fixed, with a date.

I pulled a new Docker image but the PHP version didn't change. Why?

Pulling an image only downloads it. The running container keeps using the old image until you recreate it, for example with docker compose up -d --force-recreate (after docker compose build --pull if you build your own image). Check the running container with docker exec <container> php -v, and remember the official wordpress image is built on the php image, so it needs rebuilding or re-pulling too.

How do I confirm PHP2Shell is actually fixed on my site?

Read the web-facing version in Tools › Site Health › Info › Server and compare it with the fixed releases (8.5.12, 8.4.27, 8.3.36, 8.2.35) or a vendor-backported build. If the number is lower because of a backport, confirm against the vendor advisory or the package changelog that both CVEs are addressed. On managed hosting, ask support to confirm the patch and restart in writing.

Run WordPress without a PHP runtime to patch.

Presscomet keeps your wp-admin, editor, URLs and content, and serves pages without PHP or MySQL. Check your site for free, then migrate in one click — your old site is only ever read.

Check my site