Crafting digital excellence

Loading experience 000

Development — 5 min read

PHP2Shell explained: the critical PHP flaws of October 2026 and how to fix them

Two critical bugs in PHP itself let attackers run code on a server without logging in. Here's what PHP2Shell is, who's affected, and the exact steps to patch and harden your site today.

NexDev Team
PHP2SHELL, PATCHEDREQUESTPHP workerv8.4.26v8.4.27 ✓OOM corruptionStale state$ shellUpdate PHP, restart workers, doors closed

At a glance

  1. 01Two critical PHP bugs (CVSS 9.2) allow remote code execution without a login
  2. 02Updating to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35 is the only real fix
  3. 03Turn off session upload progress and tighten request limits while you roll out the patch

On 21 October 2026, the PHP project shipped an emergency security release for two critical vulnerabilities in the PHP language itself. The security community quickly nicknamed them PHP2Shell, because in the worst case a single crafted web request can hand an attacker a shell on your server.

This isn't a bug in one plugin or one framework. It's in the engine underneath roughly three-quarters of the web: WordPress, Laravel, Magento, Drupal, custom PHP apps, all of it. If your website runs on PHP, this one is about you.

If you only read one line: update PHP to a fixed version today, then restart every PHP worker.

What happened, in plain English

PHP runs your site's code inside long-lived workers. A worker handles one request, tidies up, then handles the next one. Both bugs live in that tidy-up step.

CVE-2026-109618: "RCE via OOM corruption"

When a request hits PHP's memory_limit at exactly the wrong moment, PHP can abandon the request halfway and leave half-built internal data behind, which it later treats as valid. An attacker can trigger this with a carefully shaped multipart request (the same kind a form or file upload uses), even within your configured size limits.

On Apache with mod_php, researchers showed this works before any of your application code runs, with default settings.

CVE-2026-109619: "RCE via stale global state"

A fatal error at the wrong point can leave PHP holding a pointer to memory from a previous request. The next request on the same worker can then read memory that's already been freed (a "use-after-free"). One confirmed path goes through session upload progress, a feature that's switched on by default and runs even if your app never calls session_start().

The scorecard

CVE-2026-109618 CVE-2026-109619
Nickname OOM corruption Stale global state
Severity CVSS v4 9.2 (critical) CVSS v4 9.2 (critical)
Login needed? No No
Highest risk setup Apache + mod_php Apache + mod_php
Also affects PHP-FPM, php-cgi, FrankenPHP, LiteSpeed PHP-FPM via session upload progress

Am I affected?

Almost certainly, if you serve web pages with PHP and haven't updated since 21 October. Every release before the versions below is vulnerable:

Your branch Update to
PHP 8.5 8.5.12
PHP 8.4 8.4.27
PHP 8.3 8.3.36
PHP 8.2 8.2.35
PHP 8.1, 8.0, 7.4 No official release. Upgrade to a supported branch, or use your OS vendor's backported package

Check what you're running:

php -v                       # CLI version
php-fpm -v                   # FPM version (may be php-fpm8.3 etc.)

Or drop a temporary file on the server, open it once, then delete it immediately:

<?php echo PHP_VERSION;

One catch: Linux distributions such as Debian, Ubuntu and RHEL often backport the fix without changing the version number. If you use distro packages, check your vendor's security tracker rather than trusting php -v alone.

The fix: patch first, everything else second

Step 1 — Update PHP

On Ubuntu/Debian with the common Ondřej PPA:

sudo apt update
sudo apt install --only-upgrade 'php8.3*'    # match your branch

On RHEL, Alma or Rocky:

sudo dnf upgrade 'php*'

On Docker, bump your base image (for example php:8.3.36-fpm) and rebuild. Don't just restart the old container.

On shared or managed hosting, open your control panel's PHP selector and confirm you're on a fixed version. Many hosts patched on day one, but confirm it, don't assume it.

Step 2 — Restart every worker

Old workers keep running old code. After updating:

sudo systemctl restart php8.3-fpm     # PHP-FPM
sudo systemctl restart apache2        # mod_php

Then re-check the version from a web request, not just the CLI. They can differ.

Can't patch right now? Buy time safely

These settings reduce risk while you schedule the update. They are not a fix. Put them in php.ini or your FPM pool config, never in .user.ini or ini_set(), because those load too late to help.

; Closes the confirmed session path for CVE-2026-109619
session.upload_progress.enabled = 0

; PHP 8.5 only: closes the fatal-error backtrace path
fatal_error_backtraces = 0

; Keep request bodies small
post_max_size = 8M          ; 32M if you genuinely accept uploads
upload_max_filesize = 6M    ; always below post_max_size

Then restart workers. Beyond PHP itself:

  • Block multipart requests at your proxy or WAF on any site that doesn't accept forms or uploads.
  • Cap request size, part count and headers at the front end (Nginx, Cloudflare, your load balancer).
  • Don't rely on container memory limits or RLIMIT_AS. Researchers warn these can trigger the vulnerable code path or take down every worker at once.
  • Don't hide the problem with @ or display_errors = Off. Silencing errors doesn't stop the stale-state bug.

Wait, there's a third one

On 23 October, PHP disclosed CVE-2026-115560, a separate session bug that the 21 October releases don't fix. The good news: it only bites apps that switch session.serialize_handler to php at runtime with ini_set() before session_start(), which PHP calls "unlikely in practice."

The fix arrives in the next regular release. In the meantime, the same session.upload_progress.enabled = 0 setting from above covers it. If you've already applied it, you're done.

Are attackers using it?

Public proof-of-concept code is circulating, though each version reportedly works only on a specific mix of operating system, PHP version and web server. Exploitation attempts have been reported. CISA has urged immediate patching. Treat this as an emergency, not a backlog item.

Your 15-minute checklist

  1. Find every server, container and hosting account that runs PHP, including staging and that old microsite nobody remembers.
  2. Update each one to 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 (or your vendor's patched package).
  3. Restart PHP-FPM, Apache or your containers.
  4. Confirm the version from a web request.
  5. Set session.upload_progress.enabled = 0 for CVE-2026-115560 until the next release.
  6. If you're still on PHP 8.1 or older, plan the upgrade now. This won't be the last critical bug.

The bigger lesson

PHP2Shell is a reminder that security isn't only about your own code. The language, the server and every library underneath need looking after too. Sites that were already on a supported PHP version with someone watching updates were patched within hours. Sites on PHP 7.4 that nobody touches are still exposed.

If you're not sure where your site stands, our maintenance & growth service covers PHP upgrades, server patching and monitoring, so the next emergency release is something you hear about after it's already been handled.

Sources: The PHP Foundation, Rapid7, CISA, The Hacker News.

  • #PHP
  • #Security
  • #Hosting
  • #WordPress

Keep reading