Skip to content
Witen field notes

PHP2Shell: what WordPress, Joomla, and Matomo site owners should do now

· Witen Labs · Security advisory

Updated : PHP’s October 23 advisory: keep session upload progress off until the next PHP release. Also Sury and Remi package status, how to check backported builds, and what to do after patching.

What happened

If your WordPress, Joomla, or Matomo site runs on PHP, update PHP today or ask your host to do it. On October 21, 2026, PHP released emergency fixes for two critical flaws, together called PHP2Shell (CVE-2026-109618 and CVE-2026-109619), that let an attacker run their own code on a server without logging in.

  • Who is affected: essentially every site that serves web pages with PHP 5.4 or later, whatever your web server setup (BleepingComputer).
  • Why it’s urgent: details leaked a day early, and Cloudflare saw attack traffic before the fix shipped. One day on, Sansec reports that the public exploits don’t work against a default PHP installation and need specific conditions on the target, so mass exploitation looks less likely than first feared (Sansec). That buys you hours, not weeks.
  • It can leak secrets, too: the researchers also demonstrated reading PHP’s memory, which can hold passwords, API keys, and session tokens, without running any code on the server (PHP2Shell researchers).
  • The hard part: new official releases exist only for PHP 8.2, 8.3, 8.4, and 8.5. For 7.4, 8.0, and 8.1, PHP has published minimal source backports, and some vendors ship backported packages. PHP itself publishes nothing for 7.3 and older.
  • Update, October 23: PHP disclosed a related, much narrower flaw (CVE-2026-115560) that the October 21 releases don’t fix. Update anyway, then keep session.upload_progress.enabled=0 until the next PHP release (details below).

The flaw is in PHP itself, not in WordPress, Joomla, or Matomo, so updating those alone does not fix it.

Step 1: Find your PHP version

You need the full version number, such as 8.3.36, not just “8.3”. For official PHP releases, the last number tells you whether the fix is installed. Linux distributions, Sury, and Remi backport the fix without changing that number, so on those builds you also need the package version (see If your server gets PHP from Sury and If your server gets PHP from Remi).

  • WordPress: Tools → Site Health → Info tab → Server → PHP version.
  • Joomla: System → System Information → PHP Version.
  • Matomo: Administration → System → System Check → PHP version.
  • Hosting control panel: cPanel’s “Select PHP Version” or “MultiPHP Manager”, or Plesk’s PHP settings for your domain. These often show only “8.3”, so check inside your site as well.

If your site is managed by a developer or agency, send them this page and ask them to confirm the exact version.

Step 2: What your version means

These releases, and anything newer on the same branch, contain the fixes for both PHP2Shell vulnerabilities: 8.5.12, 8.4.27, 8.3.36, and 8.2.35 (PHP security advisory). A fixed version closes these two flaws; it doesn't make a site safe in general.

PHP versions, whether each is fixed for PHP2Shell, and what to do
Your PHP versionStatusWhat to do
8.5.12+, 8.4.27+, 8.3.36+, 8.2.35+FixedNothing for PHP2Shell. If on 8.2, plan a move: it stops getting security fixes on December 31, 2026.
Older 8.2, 8.3, 8.4, or 8.5Vulnerable, fix availableUpdate today. Ask your host if you can’t do it yourself. If the number looks old but PHP comes from your Linux distribution, check the package first (see below).
8.1, 8.0, 7.4Vulnerable, no official releaseInstall a backported package from your Linux vendor, Sury, or Remi, or ask your host for one; PHP has published minimal source backports for these branches. The version number doesn’t change, so confirm the package. Then plan a move to 8.3 or newer.
7.3 or olderVulnerable, no official fixSury and some paid long-term vendors have backported the fix as far as 5.6. Install one if you can, and move to a supported version as soon as possible.

Before switching PHP versions on a site that has been on old PHP for a long time, take a full backup and update your themes and plugins first. Old extensions are the usual reason a site breaks after an upgrade.

Patching does not remove an attacker who got in before you patched. If your site was exposed, read the section on signs of compromise below.

If your server gets PHP from Sury

Many Debian and Ubuntu servers, and the hosts and panels built on them, install PHP from Ondřej Surý’s free, volunteer-run packages: packages.sury.org for Debian, and the ppa:ondrej/php archive on Launchpad for Ubuntu. Sury shipped fixes for every branch from 5.6 to 8.5, including the end-of-life branches the PHP project no longer releases. Its changelog entries for the fix are dated October 20 and 21, before PHP’s public release at 14:00 UTC on October 21.

  • Ubuntu PPA (ppa:ondrej/php): fixed for every branch on Ubuntu 22.04 and 24.04, on every architecture, published on October 21 between 15:46 and 20:56 UTC.
  • packages.sury.org on amd64 (ordinary Intel and AMD servers): fixed for every branch on Debian 11, 12, and 13 and Ubuntu 22.04 and 24.04. The 7.2 to 8.5 package files are dated October 21, before PHP’s release; 5.6, 7.0, and 7.1 were rebuilt again on October 22.
  • packages.sury.org on ARM (arm64 and armhf): many branches still serve builds from before the fix. Mattias Geniar flagged the gap on the older branches; when we read the repository’s own indexes on October 22 (dated 14:36 to 16:01 UTC, and unchanged when we checked again at 17:20 UTC), it ran through the supported branches too. On arm64, only 8.5 on Debian 12 and 8.2 on Ubuntu 22.04 had fixed 8.2 to 8.5 builds. Debian 12 arm64 still offered 8.3.35 and 8.4.26.

ARM covers AWS Graviton, Ampere, Oracle and Hetzner ARM servers, and Raspberry Pi. Builds are landing hour by hour (Debian 12’s arm64 8.5 build arrived at 13:45 UTC on October 22), so treat this snapshot as a reason to check, not as your answer:

Sury repository branches without the PHP2Shell fix on arm64 and armhf, October 22, 2026
packages.sury.org releasearm64: no fix yetarmhf: no fix yet
Debian 12 (bookworm)5.6, 7.0, 7.1, 8.0, 8.1, 8.2, 8.3, 8.47.3, 8.1, 8.2, 8.3, 8.4, 8.5
Debian 13 (trixie)7.2, 7.3, 7.4, 8.1, 8.2, 8.3, 8.4, 8.55.6, 7.0, 7.2, 7.4, 8.1, 8.2, 8.3, 8.5
Debian 11 (bullseye)7.2, 7.3, 7.4, 8.0, 8.1, 8.2, 8.3, 8.4, 8.55.6, 8.0, 8.1, 8.2, 8.5
Ubuntu 24.04 (noble)7.0, 7.1, 7.2, 8.0, 8.2, 8.3, 8.4, 8.55.6, 7.0, 7.1, 7.2, 8.1, 8.2, 8.4, 8.5
Ubuntu 22.04 (jammy)5.6, 7.3, 7.4, 8.1, 8.3, 8.4, 8.57.1, 8.1, 8.2, 8.3, 8.4, 8.5

The first fixed Sury package on each branch is below. Your installed version must be this or later; the part after the + varies by release and repository.

First Sury package revision with the PHP2Shell fix, by PHP branch
PHP branchFirst fixed Sury package
8.58.5.12-1
8.48.4.27-1
8.38.3.36-1
8.28.2.35-1
8.18.1.34-9
8.01:8.0.30-25
7.41:7.4.33-31
7.37.3.33-35
7.27.2.34-66
7.17.1.33-80
7.07.0.33-92
5.65.6.40-104

Check your own server

On old branches the PHP version doesn’t change when the fix arrives. Sury’s fixed 8.1 still reports 8.1.34, exactly like the vulnerable one, and WordPress Site Health will show the same number. The same goes for distribution packages: Ubuntu 24.04’s fixed PHP still reports 8.3.6, as Mattias Geniar pointed out. The package version is what tells them apart. Run these over SSH:

# Which architecture is this server?
dpkg --print-architecture

# Which PHP packages are installed, at which versions?
dpkg -l | grep -E 'php[0-9.]+-(fpm|common)|libapache2-mod-php'

# Where does a package come from? Use your branch in place of 8.3.
apt-cache policy php8.3-fpm

# Does the installed package record the fix? Any output means yes.
zgrep -E 'CVE-2026-10961[89]' /usr/share/doc/php8.3-common/changelog.Debian.gz
  • apt-cache policy lists the source of each version. packages.sury.org or ppa.launchpadcontent.net/ondrej/php means Sury; deb.debian.org, security.debian.org, or archive.ubuntu.com means your distribution.
  • A packages.sury.org version looks like 8.1.34-9+0~20261021.82+debian12~1.gbp4e430a, and a PPA version like 8.1.34-9+ubuntu24.04.1+deb.sury.org+1. In both, 8.1.34-9 is the part to compare with the table above. 8.1.34-8 is vulnerable.
  • Distribution fixes: Debian 12 ships 8.2.35-1~deb12u1 and Debian 13 8.4.27-1~deb13u1 in their security archives (Debian tracker). Ubuntu 24.04 ships 8.3.6-0ubuntu0.24.04.13 and Ubuntu 22.04 8.1.2-1ubuntu2.28 (Ubuntu security).
  • Check the package that serves your site, usually php8.x-fpm or libapache2-mod-php8.x. The command-line PHP is a separate package and can be at a different version.
  • Mattias Geniar also found a quick test: fixed 8.2 to 8.5 builds know a new setting, so php -r 'var_dump(ini_get("memory_hard_limit_percent"));' prints string(0) "" instead of bool(false). Sury’s backports to 8.1 and older don’t add that setting, so use the changelog there.

Then update and restart. The fix only takes effect once PHP restarts:

sudo apt update && sudo apt upgrade
sudo systemctl restart php8.3-fpm   # or: sudo systemctl restart apache2

If you’re on ARM and your branch has no fixed build yet, don’t wait on it. On Ubuntu, switch to the PPA, which is fixed for ARM. On Debian, the quickest fixed option is usually the distribution’s own PHP (8.2 on Debian 12, 8.4 on Debian 13) or a Sury branch that is already fixed for your architecture. Until then, apply the interim settings below.

Witen’s Vulnerability Intel judges Linux packages against the Debian, Ubuntu, Alpine, Red Hat, and Gentoo security trackers. Sury and Remi aren’t among those trackers, so for their builds the package changelog and the tables on this page are the answer.

If your server gets PHP from Remi

On RHEL, AlmaLinux, Rocky Linux, and Fedora, many servers get PHP from Remi Collet’s free, community-run repository. PHP’s advisory warned it would not have updates on October 21, but the fixed packages were in the repository that afternoon: the package files are dated 13:34 to 13:53 UTC, and the repository metadata about 14:07 UTC, minutes after PHP’s release. Remi announced them on its blog on October 22.

  • What’s fixed: 8.2, 8.3, 8.4, and 8.5, plus backports to 7.4, 8.0, and 8.1, on Enterprise Linux 8, 9, and 10 and Fedora 43 and 44, for x86_64 and aarch64 (ARM). Fedora 45 offers 8.2 to 8.5 only, all fixed. ARM got its builds at the same time as x86_64.
  • Both install styles: the module streams in remi-modular, which replace the system php packages, and the parallel packages named like php81-php-common, which install beside them.
  • Not fixed yet: 7.2 and 7.3 on Enterprise Linux 8, still at builds from August, and the parallel 5.6, 7.0, and 7.1 packages there, from July.

Remi’s backports keep the upstream number too. The fixed 8.1 is 8.1.34-6 and the vulnerable one is 8.1.34-5; both report PHP 8.1.34. A module stream package looks like php-common-8.1.34-6.module_php.8.1.el9.remi and a parallel one like php81-php-common-8.1.34-6.el9.remi. Compare the part before .module or .el with this table:

First Remi package release with the PHP2Shell fix, by PHP branch
PHP branchFirst fixed Remi package
8.58.5.12-1
8.48.4.27-1
8.38.3.36-1
8.28.2.35-1
8.18.1.34-6
8.08.0.30-21
7.47.4.33-31
# Module stream install (remi-modular): which PHP, from which repository?
rpm -q php
dnf info php

# Parallel (SCL) install: use your branch in place of 81.
rpm -q php81-php-common

# The newest changelog entries. A backport names both CVEs;
# 8.2 to 8.5 say "Update to" the fixed release.
rpm -q --changelog php | head

Then run sudo dnf upgrade and restart PHP: sudo systemctl restart php-fpm for a module stream, php81-php-fpm for a parallel install, or httpd if Apache runs PHP itself.

Step 3: Ask your host

On shared or managed hosting, your host controls the PHP build, so you need them to confirm the fix. If your server gets PHP from Sury or Remi, the sections above show how to check the package yourself. Many hosts will patch without being asked, but a short ticket gets you a clear answer. Copy, fill in the brackets, and send:

Subject: PHP2Shell (CVE-2026-109618 / CVE-2026-109619) on [your domain]

Hi,

My site [your domain] runs PHP [your version]. PHP released fixes for
PHP2Shell on October 21, 2026 (8.5.12, 8.4.27, 8.3.36, 8.2.35).

1. Has the PHP serving my site been updated to a fixed release, or a
   build with the fixes backported? If so, which version or build?
2. If not, when will it be, and can I switch my site to a fixed version
   now?
3. Have you applied any interim protection (for example WAF rules) in
   the meantime?
4. Is session.upload_progress.enabled set to 0, as PHP recommends until
   its next release (CVE-2026-115560)?

Thanks,
[your name]

If the answer is vague, ask again for the exact version. “We’re aware of it” is not the same as “you’re patched.”

If you can’t update right away

None of these make a site safe; they buy time until you can update. The PHP team says only updating is a complete fix (PHP security advisory).

If you run your own server or VPS, PHP’s interim settings reduce exposure to the confirmed attack paths. Set them in php.ini or the FPM pool config, then restart every PHP worker:

  • session.upload_progress.enabled=0. Setting it with ini_set() or a .user.ini file does not work. Leave this one off after you update, too (see After you patch).
  • post_max_size of 8M if the site doesn’t take file uploads, 32M if it does, with upload_max_filesize below it.
  • On PHP 8.5 only, fatal_error_backtraces=0.
  • The advisory also covers memory_limit and container limits. Read it before changing those, since the wrong setting can make things worse.
  • If the site takes no file uploads, reject multipart/form-data requests at the web server; Sansec notes every known trigger uses that format. Syhunt’s php2shell-protection has Apache rules and a test to confirm they work.

If you’re on shared hosting, you usually can’t change these yourself. Your options:

  • Put the site behind a web application firewall. Cloudflare has deployed rules that block known PHP2Shell exploit methods on every plan with its WAF, including Free, though it describes them as temporary (Cloudflare). As Zacharias Creutznacher points out, a WAF only helps if attackers can’t go around it: make sure no DNS record (staging, ftp, direct) points at your server without the proxy.
  • Turn off what you don’t need. Disable contact forms, upload forms, and unused plugins until you’re patched.
  • Take the site offline if it handles payments or personal data and you can’t patch soon. The UK’s National Cyber Security Centre advises updating immediately or taking systems offline until patched. Sansec’s October 22 assessment is that most sites don’t need to go that far, so weigh it against what the site holds.

Keep backups current either way, stored somewhere the site itself can’t reach.

After you patch

  • Restart every PHP process. PHP-FPM, Apache, and long-running workers keep running the old code until they restart.
  • Put a real memory_limit back if you set it to -1 as a stopgap. As Mattias Geniar showed in testing the fixed builds, the fix turns memory_limit into a soft limit with a hard one above it: twice the limit up to 1G, and the limit plus 1G above that. -1 switches both off. A request that reaches the hard limit ends its PHP worker on the spot, with no error page and no line in the PHP error log, only “exited with code 137” in the PHP-FPM log. Turn on catch_workers_output = yes in your FPM pools to see which script did it, size memory for the hard limit, and leave memory_hard_limit_percent at its default.
  • Keep session.upload_progress.enabled=0 until the next PHP release. On October 23, PHP confirmed a separate flaw, CVE-2026-115560, that can still lead to code execution on the fixed releases, 8.5.12 included, and asked everyone to leave upload progress off until its next regular release (PHP advisory). Few sites are exposed: PHP’s configuration has to set session.serialize_handler to php_binary or php_serialize, and the application then has to switch it to php with ini_set() before starting a session. PHP says sites that never change the handler can leave the feature on, but you can’t easily rule that out for every plugin, and almost no site uses upload progress tracking, so turn it off in php.ini or the FPM pool. If you already set it for PHP2Shell, leave it in place. These are the conditions Felipe Daragon of Syhunt described for his proof of concept on 8.5.12 (Syhunt). Florian Roth separately relayed a trusted contact’s claim of working exploitation against 8.2.35 and 8.5.12 that this setting blocks; he said he hadn’t reproduced it. On shared hosting, ask your host to keep it off.
  • Don’t roll back if something crashes. PHP has confirmed a regression in 8.4.27 and 8.5.12 that crashes some code using SimpleXML (php-src #24488). It was fixed in PHP’s source on October 22 and isn’t in a release yet. It is a crash, not a security hole; going back to an unfixed PHP is worse.
  • Optional: set expose_php = 0 so your server stops advertising its PHP version, and use AppArmor or SELinux to limit what PHP can run. Neither fixes PHP2Shell; both are cheap hardening.

About online checkers: Assetnote’s scanner, and Aikido’s web checker built on its approach, test by pushing PHP toward its memory limit, so the deeper checks can crash a worker. Only run them against sites you own. A clean result doesn’t prove you’re patched: Aikido’s Philippe Dourassov says their checker works up to a memory_limit of about 900 MB, and Assetnote documents false alarms on fixed PHP in some low-memory configurations. The installed package is the answer; a checker is a second opinion.

Signs your site may already be compromised

Attacks began before the fix was released, so a site that was exposed on October 20–21 is worth checking even after patching. An attacker who succeeds runs code with your site’s own permissions, so they can change your site’s files and read its configuration, including database passwords.

What to check:

  • Admin or user accounts you didn’t create.
  • PHP files you don’t recognize, especially in upload folders (wp-content/uploads on WordPress, images or tmp on Joomla), where PHP files rarely belong. Watch for double extensions such as photo.php.jpg.
  • Core, theme, or plugin files changed recently when you didn’t update anything.
  • Redirects to other sites, spam pages, or new links you didn’t add.
  • New scheduled tasks or cron jobs, or a sudden jump in outgoing email.
  • Warnings from Google Search Console, your browser, or your host.
  • On your own server: new SSH keys in authorized_keys, a burst of “Allowed memory size exhausted” errors or PHP worker crashes around October 20–21, and the web server starting shells or download tools such as curl or wget. Elastic Security Labs notes that last one is how PHP break-ins usually show up, whatever the flaw. None of these prove an attack on their own.

If you find any of these:

  1. Put the site into maintenance mode or take it offline, and tell your host.
  2. Restore from a verified clean backup taken before the compromise. If you can't tell when that was, choose one from before October 20, 2026, when attacks began. Patch PHP before bringing the site back.
  3. Change every password: hosting, control panel, database, FTP/SFTP, and all site admins.
  4. Replace secret keys stored in configuration (WordPress salts in wp-config.php, Joomla’s secret in configuration.php) and any API keys the site holds.
  5. If the site handles customer data or payments, get professional help; you may have notification obligations.

Found nothing? Rotate your secrets anyway if the site ran unpatched PHP while attacks were under way. The memory leak leaves almost nothing to find, so a clean check can’t rule it out. Changing the database password, salts, and API keys costs an hour.

No clean backup? Your host’s security team or an incident response service can help with cleanup.

Free help from Witen

Updating PHP is the fix; nothing we offer replaces it. Blocking known attackers is useful defense in depth while you get there, and these are free:

Questions about this guide: support@witenlabs.com.

Sources