PHP2Shell: Check and Patch the PHP RCE Flaws on Your Server

PHP2Shell: Check and Patch the PHP RCE Flaws on Your Server

PHP2Shell: Check and Patch the PHP RCE Flaws on Your Server

On October 21, 2026 the PHP project released 8.5.12, 8.4.27, 8.3.36 and 8.2.35 to fix two flaws in PHP itself, nicknamed PHP2Shell. Both let a request from someone who is not logged in run code as the PHP worker. The bug is in the runtime, not in WordPress, Drupal or Joomla, so updating the CMS or its plugins does not close it. This guide shows who is affected, how to check a server in one command, what to do today if you cannot upgrade yet, and how to upgrade safely.

What the two flaws are

  • CVE-2026-109618, out-of-memory corruption - when a memory allocation fails, PHP can stop a request while its internal data is only half set up, and the cleanup that follows trusts that broken data. A crafted multipart request can trigger it even inside your configured size limits.
  • CVE-2026-109619, stale global state - state that belongs to one request can outlive the memory behind it. The next request served by the same worker can use that freed memory before it is reset (a use-after-free). The confirmed path goes through the session upload progress feature and fatal errors.

Both are scored 9.2 (critical) on CVSS 4.0. The PHP announcement says a working exploit was built during the research, and that the risk is highest for Apache with mod_php, where the attack runs before any application code. Several public proof-of-concept exploits appeared within days; Rapid7 reports each works only for one combination of OS, PHP version and web server, and has seen exploitation attempts. Treat it as an emergency patch.

Who is affected

Every PHP installation that serves web requests: PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. That covers almost every WordPress, WooCommerce, Drupal, Joomla, Magento, Laravel and Nextcloud server.

PHP branch Affected First fixed version
8.5 8.5.0 - 8.5.11 8.5.12
8.4 8.4.0 - 8.4.26 8.4.27
8.3 8.3.0 - 8.3.35 8.3.36
8.2 8.2.0 - 8.2.34 8.2.35
7.4, 8.0, 8.1 all no php.net release; source backports, distro or LTS vendor packages
7.3 and older all no fix

Distributions often keep the old version number and backport the fix (for example a Debian or Ubuntu package that still says 8.2.x), so on packaged PHP check your distribution's security tracker for the package, not only the number.

Check a server in one command

Save this as php2shell-check.php and run it with the same PHP that serves your site. It prints the version, whether that version predates the fix, and the two settings the stopgaps below change.

<?php
// PHP2Shell check: is this PHP build older than the October 21, 2026 fixes?
$fixed = ['8.5' => '8.5.12', '8.4' => '8.4.27', '8.3' => '8.3.36', '8.2' => '8.2.35'];
$branch = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;
echo "PHP " . PHP_VERSION . " (" . PHP_SAPI . ")\n";
if (!isset($fixed[$branch])) {
    echo "Branch $branch gets no php.net release: check your distro or LTS vendor, or upgrade to 8.4.\n";
} elseif (version_compare(PHP_VERSION, $fixed[$branch], '<')) {
    echo "VULNERABLE: upgrade to {$fixed[$branch]} or later (or a distro build with the backport).\n";
} else {
    echo "Patched upstream version ({$fixed[$branch]}+).\n";
}
echo "session.upload_progress.enabled = " . (ini_get('session.upload_progress.enabled') ? 'On' : 'Off') . "\n";
echo "post_max_size = " . ini_get('post_max_size') . ", memory_limit = " . ini_get('memory_limit') . "\n";
php php2shell-check.php

Output checked on 2026-10-24 in the official php Docker images:

PHP 8.3.30 (cli)
VULNERABLE: upgrade to 8.3.36 or later (or a distro build with the backport).
session.upload_progress.enabled = On
post_max_size = 8M, memory_limit = 128M
PHP 8.4.27 (cli)
Patched upstream version (8.4.27+).
PHP 7.2.34 (cli)
Branch 7.2 gets no php.net release: check your distro or LTS vendor, or upgrade to 8.4.

The command-line php can be a different build from the one behind your site. To check the web side, run php-fpm -v (or php-fpm8.3 -v on Debian and Ubuntu), or put the script in the web root for one request and delete it right after.

If you cannot upgrade today: stopgaps

The PHP team is clear that there is no complete mitigation and updating is the only safe choice. These settings narrow the attack while you schedule the update. Set them where the application cannot override them - php.ini or the FPM pool with php_admin_value - because ini_set() and .user.ini apply too late. Then restart every worker.

; FPM pool, e.g. /etc/php/8.3/fpm/pool.d/zz-php2shell.conf (the [www] section of your pool)
[www]
php_admin_value[session.upload_progress.enabled] = 0
php_admin_value[post_max_size] = 32M
php_admin_value[upload_max_filesize] = 30M
php-fpm8.3 -t && systemctl restart php8.3-fpm

We checked this pool file with php-fpm -t on PHP 8.4 (configuration test successful). What each line does:

  • session.upload_progress.enabled = 0 blocks the confirmed CVE-2026-109619 path, not every variant. Turn it off unless an upload progress bar depends on it.
  • post_max_size of 8M with no uploads, or 32M if the site takes uploads, with upload_max_filesize below it, as the PHP team recommends. Also cap request size at nginx (client_max_body_size 32m;) or Apache (LimitRequestBody).
  • On PHP 8.5 only, add fatal_error_backtraces = 0.
  • PHP also suggests memory_limit = -1 set by the admin, so the memory limit itself cannot be used to trigger CVE-2026-109618. Only do that with a container or cgroup memory limit around PHP, or one bad request can take the whole server's RAM. Do not use RLIMIT_AS or RLIMIT_DATA for this: they can trigger the flaw.

Hiding errors (display_errors, error_reporting, @) does not help, and an empty error log does not prove a server was not attacked.

How to upgrade

  1. Packaged PHP (Debian, Ubuntu, RHEL, AlmaLinux). Install the security update (apt update && apt upgrade, or dnf upgrade 'php*'), then restart PHP-FPM or Apache, because running workers keep the old code. Confirm the package changelog names CVE-2026-109618.
  2. Docker images. Rebuild on a fixed tag (php:8.4-fpm resolves to 8.4.27 now) with docker compose build --pull, then recreate the containers. A running container keeps the old PHP until it is replaced.
  3. PHP 7.4 - 8.1. Use your vendor's backported package, or move to 8.4. PHP 7.3 and older will never get a fix: put the site behind an allow-list or a VPN until it is migrated.
  4. After the upgrade, run the check script again and look through the web server log for unusual multipart POST requests and PHP worker crashes since October 21.

If you need a hand, managed server administration covers patching like this, and our guide to a WordPress cloud server shows a PHP-FPM setup that keeps these settings in the pool. Before you upgrade a production site, take a snapshot: backup and restore for a VM explains how.

What we did

The same week we checked every DCXV service that runs PHP and put the measures from this guide in place. Customer servers are managed by their owners: if you run PHP on a DCXV cloud or dedicated server, run the check above today. A new cloud server gets the current packages on its first apt upgrade.

Sources (checked 2026-10-24): the PHP 8.x security release announcement of October 21, 2026, the PHP advisories GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp, and the analysis by Rapid7.

PHP2Shell: Check and Patch the PHP RCE Flaws on Your Server
clouddedicatedhosting

PHP2Shell: Check and Patch the PHP RCE Flaws on Your Server

PHP2Shell (CVE-2026-109618, CVE-2026-109619) lets an unauthenticated request run code in PHP. Fixed versions, a tested check script, php.ini stopgaps and an upgrade plan.

Brotli CVE-2026-111497: Patch Node.js, Bun and Python Apps
cloudnetworkinginfrastructure

Brotli CVE-2026-111497: Patch Node.js, Bun and Python Apps

A Brotli decoder flaw (CVE-2026-111497) can run code through fetch() in Node.js and Bun or through Python HTTP clients. Fixed versions, a tested check script and the rebuild steps.

How to Size a Cloud Server for SaaS: CPU, RAM, NVMe, Backups
cloudinfrastructurepricing

How to Size a Cloud Server for SaaS: CPU, RAM, NVMe, Backups

Size a cloud server for a SaaS app in Docker and Node.js: memory budget, CPU limits, NVMe and backups, a k6 load test, full monthly price and a worksheet.

Self-Hosted AI Coding Agents on EU VPS: Hardened Setup
aicloudhosting

Self-Hosted AI Coding Agents on EU VPS: Hardened Setup

Run AI coding agents on an EU VPS with limits: disposable workspaces, egress allowlist, scoped tokens, resource caps, tested code, honest risks and server cost.

How to Migrate a Website or App to a New Cloud Server
cloudhostinginfrastructure

How to Migrate a Website or App to a New Cloud Server

A safe plan to migrate to a cloud server: pre-migration, cutover and rollback checklists, rsync and database commands, DNS TTL, hosts-file tests, limits