AI-FIRST CYBERSECURITY · Always Wise. Always Ahead. +91-95851-60363 info@semperwise.com DOVER, DE, USA

Vulnerability advisory · PHP

PHP2Shell: two critical flaws in the code every request runs.

On 21 October 2026 the PHP project released 8.5.12, 8.4.27, 8.3.36 and 8.2.35 to fix two vulnerabilities that can allow unauthenticated remote code execution — in memory management and error handling, the parts of PHP that nearly every request touches. The disclosure leaked a day early, exploitation attempts were counted in the millions within a day, and on 23 October a third, narrower CVE was announced that the fixed releases do not cover.

SemperWise Vulnerability Research 14 min read Vulnerability Intelligence
Role /orders /admin /export Guest Customer Staff Admin Staff can reach /export — privilege escalation
9.2CVSS v4.0, both CVEs (PHP)
4Supported branches fixed
MillionsAttempts reported by Cloudflare
1 moreNarrow CVE still unfixed

The two vulnerabilities

PHP’s security advisory states the problem without hedging: the four releases “fix two critical vulnerabilities that can allow unauthenticated remote code execution. All PHP users are strongly encouraged to update immediately.” The flaws are widely called php2shell — the name CISA uses in its alert.

CVE-2026-109618CVE-2026-109619
PHP’s name RCE via OOM corruption RCE via stale global state
Advisory GHSA-w8hw-w9fx-j79w GHSA-6wmf-4rv5-p3rp
What goes wrong Out-of-memory handling can interrupt PHP while internal request data is only partly initialised; request cleanup may then treat the invalid data as valid. Request-owned internal state can survive after its memory has been freed; a later request on the same worker may use it before normal initialisation resets it.
CVSS v4.0 9.2 (PHP) · v3.1 9.8 (NVD) · 8.1 (Red Hat) v4.0 9.2 (PHP) · v3.1 8.1 (NVD) · 8.1 (Red Hat)
Oldest affected (NVD) PHP 7.3.0 PHP 5.4.0
Partial mitigation Memory and request-size limits — see below session.upload_progress.enabled=0 — see below
Descriptions paraphrase php.net’s advisory of 21 October 2026. Scores are as published by each party; NVD’s affected ranges come from its CPE configurations.

The PHP Foundation’s account of what was demonstrated is the clearest statement of severity. For CVE-2026-109618: “On Apache with mod_php, an unauthenticated request can trigger this before any application code runs, and full remote code execution was demonstrated with default settings. Remote code execution was also confirmed on PHP-FPM through application-level code paths.” For CVE-2026-109619, a worker crash was confirmed and the reporter demonstrated code execution “against a real-world application running on Apache with mod_php”.

Who is exposed

PHP lists “all PHP installations serving web requests, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed”, and adds: “We consider the risk highest for mod_php, with a demonstrated exploit where an unauthenticated request can trigger the attack before any application code runs.”

How PHP is servedExposureWhy
Apache with mod_php Highest A pre-application attack path was demonstrated with default settings. The official php:*-apache Docker images use mod_php.
PHP-FPM (nginx, Apache with proxy_fcgi) High Code execution confirmed through application-level code paths. Red Hat argues RCE is “difficult in practice” on FPM because workers exit on early initialisation failures — a judgement about difficulty, not immunity.
php-cgi, FrankenPHP, LiteSpeed In scope Named in PHP’s advisory; no separate risk statement.
PHP CLI only (cron, queues, scripts) Lower Not serving web requests — but frequently the same binary package as the web SAPI, so it is patched together.
Exposure ratings are ours, derived from php.net, the PHP Foundation and Red Hat’s published statements.

And it is not only websites that call themselves “PHP sites”. CISA’s alert makes the point that “PHP is often a component of other software and prevalence may not be directly observable” — admin panels, monitoring consoles, appliances and vendor products ship their own PHP.

Fixed versions — and the end-of-life question

BranchFixed releaseNotes
8.5 8.5.12 Also fixed in 8.6.0 RC4 (pre-release)
8.4 8.4.27
8.3 8.3.36
8.2 8.2.35 Reaches end of life on 31 December 2026
8.1, 8.0, 7.4 No official release The PHP security team published minimal source backports; distributions and LTS vendors carry their own fixes
7.3 and older No release CVE-2026-109619 reaches back to 5.4 per NVD. Ubuntu ESM shipped fixes for PHP as old as 5.5
Source: php.net news archive, 21 October 2026.

CISA is blunt about unsupported versions: organisations that cannot update, “or that continue to use PHP 8.1 or earlier unsupported versions, should take PHP-based systems offline until they can be patched or updated.”

The backport trap: a lower version number can be the patched one

Linux distributions received the patches in advance and fix their own packages without changing the upstream version number. A version-only check will therefore get these hosts wrong in both directions.

DistributionFixed packageWhat `php -v` showsAdvisory
Ubuntu 24.04 php8.3 8.3.6-0ubuntu0.24.04.13 8.3.6 — patched USN-8948-1
Ubuntu 22.04 php8.1 8.1.2-1ubuntu2.28 8.1.2 — patched USN-8948-1
Debian 13 (trixie) php8.4 8.4.27-1~deb13u1 8.4.27 DSA-6574-1
Debian 12 (bookworm) php8.2 8.2.35-1~deb12u1 8.2.35 DLA-4848-1
RHEL 10 php 8.3.36-1.el10_2, php8.4 8.4.27-1.el10_2 8.3.36 / 8.4.27 RHSA-2026:87070, RHSA-2026:87071
RHEL 9 / RHEL 8 Module streams php:8.2 (and php:7.4 on RHEL 8) Varies by stream RHSA-2026:87072, RHSA-2026:87073, RHSA-2026:87080
Status on 23–24 October 2026 from each distribution’s security tracker. A host on Ubuntu 24.04 reporting PHP 8.3.6 is fixed; a vendor-built 8.3.35 is not.

The reverse case matters just as much. PHP from a third-party repository — Ondřej Surý’s builds being the commonest on Debian and Ubuntu — follows upstream numbering, so on those hosts a version below the fixed release really is vulnerable, even though the package name looks like the distribution’s own. Sury published fixed builds for PHP 7.4 through 8.5 on 21 October.

How to find every PHP that is serving requests

Three facts make PHP inventory harder than it looks. The CLI on the PATH is not necessarily the PHP that serves the web. One server often runs several PHP-FPM versions side by side. And a patched package does nothing until every worker has been restarted.

On each server
# The CLI — useful, but it is not necessarily what serves the web
php -v

# Debian / Ubuntu: every PHP package, including the Apache module and each FPM version
dpkg -l 'php*' 'libapache2-mod-php*' 2>/dev/null | awk '/^ii/{print $2, $3}' | grep -E 'php[0-9.]*(-fpm|-cgi|-cli)?$|mod-php'
ls /etc/php/                               # one directory per installed branch

# Which SAPI actually serves requests
apache2ctl -M 2>/dev/null | grep -i php    # mod_php loaded? (php_module / php7_module)
systemctl list-units --type=service 'php*-fpm*' --no-legend
for f in /usr/sbin/php-fpm*; do "$f" -v | head -1; done

# RHEL / Alma / Rocky
rpm -q php php-fpm php-cli 2>/dev/null
dnf module list --enabled php 2>/dev/null

# Alpine
apk info -v 2>/dev/null | grep -E '^php[0-9]*-(fpm|cgi|apache2|common)?'
Restarts and containers
# Restart every worker after patching — then prove it happened
sudo systemctl restart php8.4-fpm          # repeat per FPM version
sudo systemctl restart apache2             # mod_php lives inside Apache's children
ps -o pid,lstart,cmd -C php-fpm8.4         # start times must be after the upgrade
ps -o pid,lstart,cmd -C apache2

# Containers: the PHP inside each running container, then rebuild and redeploy
docker ps --format '{{.ID}} {{.Image}}' | while read -r id img; do
  printf '%s %s ' "$id" "$img"; docker exec "$id" php -r 'echo PHP_VERSION, " ", PHP_SAPI, PHP_EOL;' 2>/dev/null || echo 'no php'
done

Two shortcuts to avoid. The X-Powered-By header shows a version only when expose_php is on — most hardened servers turn it off, and on distribution builds it shows the misleading upstream number anyway. And a Composer config.platform.php value describes what the project was resolved against, not the runtime it is running on.

If you cannot update immediately

PHP’s position is unambiguous: “while only an update is a complete solution, the following measures reduce exposure to specific attack paths but do not make an installation safe.” In summary:

For CVE-2026-109618

  • Set memory_limit=-1 in a way applications cannot override (php_admin_value in the FPM pool or Apache configuration), and check that no pool, directory or application setting puts a finite limit back. PHP notes an underlying allocation failure can still reach the vulnerable path.
  • Set a low post_max_size: 8M where uploads are not needed, 32M where they are, with upload_max_filesize below it.
  • Enforce request limits at the web server or proxy — decoded size, input-field count, multipart part count, header count and nesting depth — including for requests without a usable Content-Length.
  • Use a container or cgroup memory limit as an availability boundary. PHP warns specifically not to substitute RLIMIT_AS or RLIMIT_DATA, which can cause the vulnerable allocation failure.

For CVE-2026-109619

  • Set session.upload_progress.enabled=0 in php.ini, the FPM pool or server configuration — not with ini_set() or .user.ini — and restart every worker. PHP: “This blocks the confirmed session paths but not other variants.”
  • On PHP 8.5, set fatal_error_backtraces=0 and restart every worker. This blocks one confirmed path only.
  • Remove invalid or deprecated per-request settings that emit diagnostics before initialisation. Suppressing diagnostics with error_reporting, display_errors or @ does not help.
  • Fix the fatal-error conditions and execution time-outs an attacker can reach — in callbacks, upload and import processing, and cleanup.

A web application firewall can buy time. Cloudflare enabled rules for all plans, including free, from 03:02 UTC on 21 October, and AWS published AWS WAF guidance. Cloudflare itself reported attackers mutating payloads to get past its rules, and CISA says only that a WAF “may provide some protection”. It is a bridge to the update, not a replacement for it.

A disclosure that did not go to plan

When (UTC)What happenedSource
2024 First signs of the out-of-memory problem found while fixing an issue from an external audit (Quarkslab, organised by OSTIF, funded by the Sovereign Tech Agency). Work on a fix stalled repeatedly. PHP Foundation
11 Aug 2026 Researcher Ryan A at Calif reports an unconditional RCE with the same root cause; OpenAI independently reports it too. Wiz (24 Aug) and OpenAI (18 Sep) report further vectors. PHP Foundation
17 Oct An exploitation attempt appears in Amazon’s MadPot honeypot telemetry — four days before disclosure. Amazon notes it is unclear whether it would have succeeded on real systems. Amazon Threat Intelligence
20 Oct, ~15:00 The two CVE IDs leak on forums and social media, with a wrong CVSS of 10.0. PHP pre-announces at 19:30 and moves the release forward a day. A reporter’s proof-of-concept video is published by mistake. PHP Foundation
21 Oct, 02:00–08:00 Multiple proof-of-concept exploits appear and are used against honeypots almost immediately. Cloudflare rules go live at 03:02. Amazon; Cloudflare
21 Oct, 07:41 Chainguard publishes fixed images six hours before the coordinated release — in the PHP Foundation’s words, breaking the embargo. PHP Foundation
21 Oct, 14:00 PHP 8.5.12, 8.4.27, 8.3.36, 8.2.35 released. CISA alert; CERT-In issues CIVN-2026-0510 (Critical). php.net; CISA; CERT-In
22 Oct Social-media claims that fixed releases are still exploitable. A PHP security team member calls the first such report an unrelated, minimal-impact crash. oss-security
23 Oct PHP announces CVE-2026-115560 (below). CISA updates its alert with a SIGMA detection rule. php.net; CISA
Times as published by each source.

Exploitation status, as of 23 October 2026

The public record says two different things, and both are accurate. Attempts are enormous. Cloudflare’s chief executive, Matthew Prince, said on X that the company saw thousands of exploitation attempts in the ten hours before the announcement, tens of thousands within 45 minutes of disclosure, hundreds of thousands within two hours, and millions since (as reported by The Register). CERT-In’s note states that “multiple reports confirm large scale exploitation in the wild”.

Confirmed successful compromise is less clear. CISA wrote that it “has not observed successful exploitation of these vulnerabilities in the wild as of the time of publication”, and neither CVE was in its Known Exploited Vulnerabilities catalogue on 23 October. The gap between “attempted” and “confirmed” usually closes in days, not weeks. Treat any unpatched, internet-facing PHP as presumed targeted, and follow CISA’s advice to watch for “PHP worker processes launching shells or downloading tools”.

CVE-2026-115560: the third vector the patch does not fix

On 23 October PHP published an informational advisory: “We suggest you set session.upload_progress.enabled=0 until the next regular bugfix release, to fully protect from an unlikely RCE vector.” It affects fully patched releases, including 8.5.12.

The preconditions are narrow. An application must set session.serialize_handler to php_binary or php_serialize in configuration, then switch it to php at runtime with ini_set() before calling session_start() — with session upload progress still enabled. Applications that never change the serialize handler at runtime are not affected. PHP will publish a full advisory with the next regular release. If you already applied the CVE-2026-109619 mitigation, it covers this too.

How SemperWise helps

Graded against the fix, not the number

The optional Sentinel agent reports each machine’s installed PHP packages, and SemperWise One raises CVE-2026-109618 and CVE-2026-109619 as Critical findings on supported-branch builds below the fixed releases — including Sury builds on Debian, which carry the Debian team’s name and are easy to mistake for distribution packages. End-of-life branches are raised as unsupported, because a backported fix can hide behind an unchanged version number.

Backports read from the source

A credentialed patch audit reads your distribution’s own advisories, so an Ubuntu 24.04 host on `8.3.6-0ubuntu0.24.04.13` is reported as fixed and an Ubuntu host one package behind is not — the case version-only scanners get wrong both ways.

The PHP nobody listed

External testing and attack-surface discovery find the PHP inside admin panels, vendor appliances and forgotten microsites — the components CISA warns “may not be directly observable”.

Configuration, not just version

Where an update has to wait, we verify that the interim mitigations are really in force — for example, that `session.upload_progress.enabled` is off for the pool that serves requests, not just in the CLI’s php.ini.

Closed when it is actually fixed

Findings re-check on every inventory and close only when the fixed package is installed; they reopen if an old image or snapshot comes back.

Questions people ask about this

Which PHP versions fix php2shell?
PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35, released on 21 October 2026, fix CVE-2026-109618 and CVE-2026-109619. PHP 8.1 and older get no official release; the PHP security team published source backports for 7.4, 8.0 and 8.1, and distributions such as Ubuntu, Debian and Red Hat ship their own patched packages for the versions they support.
Our Ubuntu server reports PHP 8.3.6. Is it vulnerable?
Not necessarily. Ubuntu backports security fixes without changing the upstream version, so PHP 8.3.6 on Ubuntu 24.04 is patched once the package is 8.3.6-0ubuntu0.24.04.13 or later (USN-8948-1). Check the package version with dpkg -l php8.3, not the number php -v prints — and restart PHP-FPM and Apache afterwards.
Is disabling session upload progress enough?
No. PHP describes session.upload_progress.enabled=0 as blocking the confirmed session paths of CVE-2026-109619 “but not other variants”, and it does nothing for CVE-2026-109618. Updating is the only complete fix. The setting is still worth applying after you update, because it also closes the narrow CVE-2026-115560 vector announced on 23 October.
Are the patched versions really still exploitable?
For CVE-2026-109618 and CVE-2026-109619, no confirmed report shows exploitation of the fixed releases. The one acknowledged issue affecting fixed versions is CVE-2026-115560, which requires an application to switch its session serialize handler at runtime with upload progress enabled — an unusual setup that PHP will fix in its next regular release.
We run PHP-FPM, not mod_php. Can we wait?
No. PHP names PHP-FPM as affected, and the PHP Foundation says code execution was confirmed on FPM through application-level code paths. Red Hat judges exploitation harder on FPM, which is a statement about difficulty rather than safety. Update and restart every pool.

SemperWise Vulnerability Research

Advisories & Patch Intelligence

Reads vendor advisories, CVE records, distribution trackers and government alerts the day they publish, and turns them into the version tables, detection steps and fix guidance our assessment teams work from. Every version number and quote is checked against its original source.

Next step

Talk to us about your next assessment.

A 30-minute call, then a scope document with what is in, what is out and what it costs. No obligation, and no charge for the conversation.