Guide

PHP2Shell (CVE-2026-109618 and CVE-2026-109619): what to do on a VPS and on shared hosting

Two bugs in PHP itself, fixed on 21 October 2026. On a server you run, the fix is an update and a restart. On shared hosting only the hosting company can apply it, so this page says what you can do in the meantime and exactly what to ask them.

The short answer

PHP2Shell is the name for CVE-2026-109618 and CVE-2026-109619, two critical bugs (CVSS v4.0 9.2) in the PHP engine that can let a request with no login run code on the server. php.net fixed them on 21 October 2026 in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. PHP 8.1 and older get no php.net release, only vendor builds that usually keep their old version number. The fix is updating PHP and restarting every PHP worker; updating WordPress or a plugin does not help. On shared hosting only the host can update PHP: check your PHP branch in the control panel, ask the host to confirm the fixed build from its changelog, and rotate the site's passwords and keys once it has.

What PHP2Shell is

PHP2Shell is two separate bugs in how the PHP engine cleans up after a request that fails partway through. They were found by researchers at Calif, Wiz Research and OpenAI. Calif first reported one to the PHP project on 11 August 2026 (Sansec's timeline), details leaked on 20 October, and php.net released the fixes on 21 October at 14:00 UTC.

php.net says every PHP installation that serves web requests is at risk: PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. It considers the risk highest for mod_php, where it demonstrated an exploit that runs before any application code does. The bugs are in PHP, not in WordPress, Magento or any plugin, so updating the application does not fix them.

CVEphp.net advisoryWhat goes wrongSeverity
CVE-2026-109618GHSA-w8hw-w9fx-j79w, "RCE via OOM corruption"When PHP runs out of memory while a request is still being set up, the cleanup can treat half-built internal data as valid. The advisory's examples include multipart/form-data requests built to exhaust memory_limit.CVSS v4.0 9.2, critical
CVE-2026-109619GHSA-6wmf-4rv5-p3rp, "RCE via stale global state"A fatal error can leave a PHP worker holding pointers into memory that a finished request owned, and the next request on that worker uses them. Confirmed through session upload progress, and through fatal_error_backtraces on PHP 8.5.CVSS v4.0 9.2, critical

Sansec reports that one of the paths also returns freed worker memory to the visitor inside the PHPSESSID cookie, and that this memory can hold passwords, session tokens, API keys and TLS private keys from other requests, even on a site that never starts a session. That is why the last step on this page, for every kind of hosting, is rotating secrets.

Which PHP versions fix it

php.net supports PHP 8.2 and later. Older branches are fixed only by vendors, and a vendor's fixed build usually keeps the version number it had, so on those branches the version alone does not tell you whether you are patched.

PHP branchFixed inWhere the fix comes from
8.58.5.12php.net, 21 October 2026
8.48.4.27php.net, 21 October 2026
8.38.3.36php.net, 21 October 2026
8.28.2.35php.net, 21 October 2026
8.1, 8.0 and 7.4No php.net releaseVendor builds that keep the version number (distributions, Plesk, cPanel, CloudLinux, Ondřej Surý, paid extended support), or the PHP security team's source backports for people who build PHP themselves
7.3 and olderNo php.net fix or backportwatchTowr says none is available and to upgrade. CloudLinux has rebuilt its packages back to 5.2, Ondřej Surý's repository covers 5.6, and Plesk points to paid TuxCare support for 5.6, 7.2 and 7.3

Is it being exploited? What the sources said by 23 October 2026

  • Cloudflare says it saw attack traffic aimed at its customers after the details leaked and before the fix was released, and that its WAF rules were live from 03:02 UTC on 21 October.
  • watchTowr says it has observed exploitation in the wild since 21 October through its honeypot network (FAQ updated 22 October).
  • CISA had not observed exploitation when it published its alert on 21 October. Neither CVE was in CISA's Known Exploited Vulnerabilities catalogue as of 22 October, according to watchTowr.
  • Sansec's update of 22 October: the public proof-of-concept exploits do not work against a default PHP installation, most need the target application to also have a local file inclusion bug, and mass exploitation is less likely than it first expected. It still says to update PHP.
  • CISA says that anyone who cannot update immediately, or who still runs PHP 8.1 or earlier, should take PHP-based systems offline until they are patched or updated.

On shared hosting: what you can and cannot do

On a shared hosting plan (a cPanel, Plesk or DirectAdmin account, or a host's own panel), the hosting company installs PHP and runs it for every site on the server. You cannot patch it yourself, and nothing you change inside WordPress, a plugin or your own files fixes these bugs. What you can do is find out where you stand, put up a temporary block if the site can manage without uploads for a few days, and get a clear answer from the host.

  • You cannot update PHP, restart its workers, or change the server-wide PHP settings that php.net lists as stopgaps. Only the host can patch PHP.
  • You can check which PHP branch the site uses and move it to 8.2 or newer, add a temporary .htaccess rule that blocks multipart requests, ask the host the questions below, and rotate the site's secrets once PHP is fixed.

Shared hosting: check which PHP your site runs

In cPanel, open MultiPHP Manager: it lists each of your domains with the PHP version it uses, or "Inherited" if it follows the server default. On hosts running CloudLinux, the cPanel page is Select PHP Version, where you choose from the versions the host allows. Other panels show it in the site's PHP settings.

If the site is on 8.1 or older, move it to 8.2 or newer once you have checked that the site works on it, on a staging copy if the host offers one. php.net supports 8.2 and later and ships every fix for them; anything older depends on the host's vendor rebuilding each fix in turn.

The version number cannot tell you whether you are patched. Hosting panels ship backported builds: CloudLinux's fixed alt-php83 is 8.3.35-6, below php.net's 8.3.36, and Plesk's fixed 8.1, 8.0 and 7.4 keep their old numbers with a new build date. cPanel fixed every EasyApache 4 PHP from 7.4 to 8.5 on 21 October, and CloudLinux fixed its alt-php and ea-php builds back to 5.2, so on a host that has run its updates even an older branch can be patched. Whether it has run them is the first question to ask.

Shared hosting: a temporary .htaccess block

Every known trigger is a multipart/form-data request, the format browsers use to upload files (Sansec). Apache and LiteSpeed read rules from a .htaccess file in the site's folder, and a rewrite rule there refuses those requests before PHP reads them. Add these lines at the top of the .htaccess file in the site's document root (usually public_html):

RewriteEngine On
RewriteCond %{HTTP:Content-Type} multipart/form-data [NC]
RewriteRule ^ - [F]

This is the rule Sansec published for an Apache VirtualHost, placed where a hosting account can reach it. It answers every multipart request with a 403, so file uploads stop working: the WordPress media library, product images, attachments on contact forms. Some forms that upload nothing still submit as multipart, and Sansec notes that some stores send cart and checkout forms that way, so test every form that matters after adding it.

To confirm it is active, try an upload in the site's admin: it should now fail with a 403 Forbidden error. If the upload still works, the host is not applying the rule, and only the host can block these requests.

It is a stopgap, not a fix: it blocks the known way in, not the bugs. It does nothing on a host that runs nginx alone, because nginx ignores .htaccess. Remove it once the host confirms PHP is fixed.

Shared hosting: what php.ini tricks and Cloudflare cannot do

php.net's stopgap for the confirmed CVE-2026-109619 session paths is turning off session.upload_progress, and it says where: in php.ini, a PHP-FPM pool, or server configuration that applies before PHP parses the request. It says not to rely on ini_set() or on a .user.ini file. Those two are the routes a plugin or a file in your own folder takes, so the setting has to be made by the host; on CloudLinux, the host sets it for every alt-php version in /etc/cl.selector/global_php.ini. Some panels let a site owner change PHP options, and whether a given screen applies early enough depends on how the host runs PHP, so ask rather than assume. The memory_limit change php.net suggests for CVE-2026-109618 is in the same position: it belongs where applications cannot override it.

If the site is behind Cloudflare, its WAF has carried PHP2Shell rules since 03:02 UTC on 21 October, on by default on every plan with the WAF, the free plan included. Pro, Business and Enterprise customers should check that the Managed Ruleset is deployed in block mode. Cloudflare also says attackers were changing their payloads to get past the rules, and to patch PHP anyway.

A WAF in front of a site only sees the traffic that goes through it. Anyone who learns the server's own IP address can send requests straight to it, and on shared hosting that address serves every site on the server. Cloudflare helps only if the server accepts web traffic from Cloudflare alone, and on shared hosting that is the host's firewall, not a setting a site owner controls. Treat it as a layer, not as the fix. The same goes for Imunify360 on CloudLinux hosts: CloudLinux says to keep its WAF on with ruleset 8.84 or later, and that this reduces the risk without replacing the update.

Shared hosting: what to ask your host

Send these in one message. A host that has patched can answer all of them in a sentence each.

  • "Has the PHP that runs my site been updated for CVE-2026-109618 and CVE-2026-109619, and on what date?"
  • "Please confirm it from the package changelog, not the version number." Fixed panel builds often keep their version, so "you are on 8.3.35" does not answer the question.
  • "Were the PHP workers restarted after the update?" A worker started before the update keeps running the old code. CloudLinux notes that on LiteSpeed a web server restart does not always stop running lsphp processes.
  • "Is every PHP version offered in my panel fixed, including the old ones, and which have no fix?" CloudLinux, for example, has no fixed build of alt-php44 or alt-php51.
  • "Is the control panel's own PHP patched?" cPanel and Plesk run their own interfaces on their own PHP, and on cPanel that includes Roundcube webmail. cPanel fixed it in cPanel & WHM 138.0.18, 136.0.50, 134.0.66 and 110.0.153; Plesk in Obsidian 18.0.80 Update 11 and 18.0.81 Update 4.
  • "If it is not patched yet, when will it be, and what protects the server until then?" A multipart block, WAF rules and the php.ini settings are all partial. CISA's advice for a system that cannot be patched is to take it offline.

After PHP is patched: rotate what the site holds

Because one path can leak memory from other requests (Sansec), assume anything the site held in memory may have been read. Rotate after the host confirms the fix, not before: a secret changed on an unpatched server can leak the same way. The same applies on a VPS.

  • Every admin and editor password for the site, and the hosting control panel, FTP and SFTP passwords.
  • The database password, then the copy of it in the site's configuration (wp-config.php on WordPress).
  • The keys that sign sessions and cookies: on WordPress, new keys and salts in wp-config.php, which also signs everyone out.
  • API keys and tokens stored in the site or its plugins: payment gateways, mail services, storage and analytics.
  • The TLS certificate's private key, if you manage it. Where the host issues certificates for you, ask whether it is reissuing them.
  • Then look for what an intruder would leave: admin accounts you did not create and PHP files you did not upload. CISA's hunting advice for whoever runs the server is to watch for PHP worker processes launching shells or downloading tools.

On a VPS or dedicated server: update, restart, verify

On a server you run, the fix is the same everywhere: install the fixed PHP from wherever your PHP came from, restart every process that runs PHP (PHP-FPM, Apache if it loads mod_php, LiteSpeed's lsphp), and check the package changelog for the two CVE numbers. The changelog is the proof, because distribution and panel builds backport the fix without taking php.net's version number. One server can carry PHP from several sources at once: a Plesk or cPanel server usually has the panel's builds beside the distribution's, and each needs updating.

Fixed PHP packages in the distributions' own advisories, as OSV carried them on 23 October 2026
ReleaseSource packageFixed inAdvisory
Ubuntu 24.04 LTSphp8.38.3.6-0ubuntu0.24.04.13USN-8948-1, 21 October
Ubuntu 22.04 LTSphp8.18.1.2-1ubuntu2.28USN-8948-1, 21 October
Debian 12 (bookworm)php8.28.2.35-1~deb12u1Debian security tracker, 21 October
Debian 13 (trixie)php8.48.4.27-1~deb13u1Debian security tracker, 21 October
Rocky Linux 9php (8.0, the default stream)8.0.30-8.el9_8.1RLSA-2026:87151, 22 October
Rocky Linux 9php:8.2 module stream8.2.35-1.module+el9.8.0+40395+2f706e64RLSA-2026:87072, 22 October
Rocky Linux 9php:8.3 module stream8.3.36-1.module+el9.8.0+40396+4e680bb7RLSA-2026:87079, 22 October
AlmaLinux 9php:8.3 module stream8.3.36-1.module_el9.8.0+330+fdc30075ALSA-2026:87079, 21 October

A release or stream missing from the table had no advisory naming either CVE in OSV on 23 October. That is not the same as unaffected: check its changelog. Ubuntu's numbers sit far below php.net's because Ubuntu backports the fix into the version each release shipped; Debian's carry php.net's own 8.2.35 and 8.4.27.

PHP from the distribution (Ubuntu, Debian, Rocky Linux, AlmaLinux)

Why
The php8.x packages on Debian and Ubuntu, or the php packages and module streams on Rocky Linux and AlmaLinux. The fixed versions are in the table above.
Apply
Debian and Ubuntu
sudo apt update && sudo apt upgrade
sudo systemctl restart php8.3-fpm   # your branch; once per installed branch
sudo systemctl restart apache2      # only if Apache loads mod_php
Rocky Linux and AlmaLinux
sudo dnf update 'php*'
sudo systemctl restart php-fpm
Verify
Debian and Ubuntu
zgrep -E 'CVE-2026-10961[89]' /usr/share/doc/php8.3-common/changelog.Debian.gz
Sansec's check, with your branch in place of 8.3. Both CVE numbers should print.
Rocky Linux and AlmaLinux
rpm -q --changelog php-common | grep -E 'CVE-2026-10961[89]'

PHP from Ondřej Surý's repository (deb.sury.org, ppa:ondrej/php)

Why
The same package names as Debian and Ubuntu use, built separately. For 8.2 and later it publishes php.net's releases: its 8.2.35, 8.3.36, 8.4.27 and 8.5.12 builds for Ubuntu 24.04 and 22.04 went up on 21 October, beside rebuilt 8.1.34 and 8.0.30 that keep their numbers. Sansec lists its fixed older branches as 5.6, 7.4, 8.0 and 8.1.
Apply
Debian and Ubuntu
sudo apt update && sudo apt upgrade
sudo systemctl restart php8.3-fpm   # your branch; once per installed branch
Verify
Debian and Ubuntu
php8.3 -v | head -1
For 8.2 and later the first line should name 8.2.35, 8.3.36, 8.4.27, 8.5.12 or later. For 8.1 and older, check the changelog as for the distribution's packages.

Plesk

Why
Plesk builds its own PHP under /opt/plesk/php. Fixed on 21 October: 8.2.35, 8.3.36, 8.4.27 and 8.5.12, plus the end-of-life 7.4.33, 8.0.30 and 8.1.34 rebuilt that day with the same numbers. The panel's own PHP (sw-engine) is fixed in Plesk Obsidian 18.0.80 Update 11 and 18.0.81 Update 4.
Apply
Plesk for Linux
plesk installer update
Or Tools & Settings > Updates > Update Components in the panel. Plesk restarts the service of a component it updates. If apt stops with NO_PUBKEY 5B6AB2160B50DB96 on Ubuntu or Debian, Plesk has a separate article for that error.
Verify
Plesk for Linux
plesk version
/opt/plesk/php/8.3/bin/php -v
Run the second line for each installed branch. A supported branch should report its fixed version. 8.1, 8.0 and 7.4 keep their number, so look for a build date of 21 October 2026 or later ("built: Oct 21 2026") in the first line.

cPanel (EasyApache 4) and CloudLinux

Why
cPanel's EasyApache 4 25.91 (21 October) fixed ea-php74 through ea-php85, and cPanel & WHM 138.0.18, 136.0.50, 134.0.66 and 110.0.153 fixed the PHP the panel itself runs. On CloudLinux, fixed ea-php and alt-php builds reach back to 5.2 (none for alt-php44 or alt-php51); CloudLinux says an update run before about 01:00 UTC on 22 October found nothing, so run it again. These builds keep a version below php.net's, so check the changelog.
Apply
CloudLinux, with CloudLinux's own commands
yum clean all && yum update 'alt-php*' 'ea-php*' -y
/scripts/restartsrv_httpd
/scripts/restartsrv_apache_php_fpm
On a cPanel server without CloudLinux, update the ea-php packages the same way (yum update 'ea-php*'), and cPanel & WHM itself from WHM. Under LiteSpeed, also run /usr/local/lsws/bin/lswsctrl restart and pkill lsphp: a web server restart does not always stop running lsphp processes.
Verify
cPanel and CloudLinux
for p in $(rpm -qa 'ea-php*-php-cli' 'alt-php*-common' --qf '%{NAME}\n'); do echo "$p $(rpm -q --changelog $p | grep -cE 'CVE-2026-(109618|109619)')"; done
CloudLinux's check. Every installed package must print 1 or more.

PHP 8.1 and older: a vendor build or an upgrade

php.net no longer releases 8.1 or older. The PHP security team published minimal source backports for 7.4, 8.0 and 8.1 for people who build PHP themselves, and several vendors have rebuilt their packages. Otherwise the answer is to move to 8.2 or newer.

  • Ubuntu 22.04: its own php8.1 is fixed in 8.1.2-1ubuntu2.28 (USN-8948-1).
  • Ondřej Surý's repository: 5.6, 7.4, 8.0 and 8.1 (Sansec).
  • Remi's repository: 7.4, 8.0 and 8.1 according to Sansec on 22 October. php.net had warned on 21 October that it would have no updates that day and urged its users to switch to distribution packages or build from source.
  • Plesk: 7.4.33, 8.0.30 and 8.1.34 rebuilt on 21 October. For 5.6, 7.2 and 7.3, Plesk recommends paid TuxCare Extended Lifecycle Support.
  • cPanel: ea-php74, ea-php80 and ea-php81 carry the backport (EasyApache 4 25.91, with 25.92 adding it to their change logs). CloudLinux: alt-php and ea-php builds for every branch from 5.2, except alt-php44 and alt-php51.
  • Extended support, per Sansec's list: TuxCare ELS for PHP, ZendPHP LTS and Freexian ELTS for Debian 9 to 11 (all paid), and Ubuntu Pro for Ubuntu 14.04 to 20.04.
  • The official Docker php image gets no fix for 8.1 or older (Sansec).
  • If none of these applies and the server cannot be upgraded, CISA's advice is to take it offline until it is.

If you run the server and cannot update today

These are partial. php.net says only an update is a complete solution, and that the measures below reduce exposure to specific attack paths without making an installation safe. On shared hosting they are the host's to apply.

  • Block multipart/form-data at the web server (Sansec). In nginx, in every server block that passes requests to PHP: if ($http_content_type ~* "multipart/form-data") { return 403; }, then nginx -t && systemctl reload nginx. In Apache, the three rewrite lines from the .htaccess section, in every VirtualHost that serves PHP. Uploads stop working until you remove it.
  • Turn off session upload progress, which blocks the confirmed CVE-2026-109619 session paths only (php.net): session.upload_progress.enabled = 0 in php.ini for mod_php, or the pool lines below for PHP-FPM, then restart every worker. Not with ini_set() and not with .user.ini.
  • Remove the controllable memory limit (php.net, for CVE-2026-109618): memory_limit = -1, set where applications cannot override it, and check that no pool, directory or application puts a finite limit back. One request can then use all of the server's memory, so watch it and restore the limit after updating (Sansec).
  • Keep post_max_size low: 8M where the application takes no uploads, 32M where it does, with upload_max_filesize below it (php.net).
  • On PHP 8.5, set fatal_error_backtraces = 0 and restart every worker. This blocks the confirmed backtrace path only (php.net).
  • Do not cap memory with RLIMIT_AS or RLIMIT_DATA: php.net says they can cause the very allocation failure the bug needs.
; every PHP-FPM pool, for example /etc/php/8.3/fpm/pool.d/www.conf
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[memory_limit] = -1

Then reload the pool (systemctl reload php8.3-fpm, with your branch) and confirm the values from a request that PHP-FPM serves, not from php -i on the command line, which does not read the pool's settings (Sansec).

What SecAI does and does not do about PHP2Shell

SecAI is a Linux server security agent, so it can only help on a server where you have root. This is exactly what it covers for these two CVEs today.

  • It matches installed packages against OSV.dev every twelve hours on Ubuntu, Debian, Alpine, Rocky Linux and AlmaLinux, and keeps each OSV answer for up to 24 hours, so a new advisory can take a day and a half to become a finding. The distributions' advisories for both CVEs were in OSV by 22 October for Ubuntu 22.04 and 24.04, Debian 12 and 13, Rocky Linux 9 and AlmaLinux 9. A SecAI finding for either CVE had not yet been confirmed on a real server when this page was written, so do not wait for one: use the changelog checks above.
  • It does not check the PHP that Plesk, cPanel or CloudLinux install (the plesk-php, ea-php and alt-php packages). A server whose sites run on panel PHP gets no PHP2Shell finding from SecAI, patched or not. Use the changelog checks above.
  • A build from Ondřej Surý's repository uses the distribution's package names, and SecAI compares it against the distribution's own fixed version, which says nothing about whether that build is fixed. Check Surý builds by their version, as above.
  • It does not update PHP, restart PHP workers or change PHP settings. Its install action only installs a few security tools, such as fail2ban.
  • It cannot help on shared hosting: the agent needs root on the server, which a hosting account does not have.
  • After the fact, it reports a PHP file in a web root that matches a web-shell signature or was recently modified, and a process running from /tmp, /var/tmp or /dev/shm, each with its evidence. It has no detection for the signal CISA names, a PHP worker process launching a shell.

Related

Questions people ask

Sources

Every source was read on 23 October 2026. Where the sources disagree, the page says whose account it gives. The distribution fixed versions are from each distribution's advisory as OSV.dev carried it that day.

Then check the rest of the server

If you run the server, the free assessment is one read-only command that checks how it is set up: SSH, the firewall, waiting security updates and signs of compromise. It does not check PHP for PHP2Shell; the changelog commands above do that.