Security· Security Disclosure

PHP's October 2026 Critical RCEs: CVE-2026-109618 and CVE-2026-109619

PHP fixed two critical (CVSS 9.2) unauthenticated RCEs in 8.5.12, 8.4.27, 8.3.36, and 8.2.35. Proofs of concept are circulating: patch every PHP server now.

Atlas Security
Security Advisories
16 min read · 3,460 words

Overview

PHP released fixes on October 21, 2026 for two critical vulnerabilities, CVE-2026-109618 and CVE-2026-109619, known together as php2shell. Both allow unauthenticated remote code execution (RCE), and both are rated CVSS v4.0 9.2. The fixed releases are 8.5.12, 8.4.27, 8.3.36, and 8.2.35. The bugs are in PHP itself — in the request setup and cleanup that wrap every script — and PHP says every installation that serves web requests is at risk. Its verdict: "there are no complete mitigations, updating is the only safe choice."

Why it's urgent: PHP is the server-side language of about 69% of websites whose language is known (W3Techs). The details leaked two days before the planned disclosure, proofs of concept are circulating, and watchTowr reports exploitation in the wild. See the timeline.

Key facts

FieldDetail
CVEsCVE-2026-109618, "RCE via OOM corruption" (GHSA-w8hw-w9fx-j79w) · CVE-2026-109619, "RCE via stale global state" (GHSA-6wmf-4rv5-p3rp)
SeverityCritical — CVSS v4.0 9.2 for both, per PHP (AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H). Red Hat rates both Important on RHEL; see risk by server API.
WeaknessMemory corruption in request memory handling: use-after-free (CWE-416), plus CWE-755, CWE-824, and CWE-1325
ImpactUnauthenticated RCE as the web server's user, from both. CVE-2026-109619 can also disclose worker memory. PHP built working exploits; mod_php is the demonstrated case.
Fixed in8.5.12 · 8.4.27 · 8.3.36 · 8.2.35 (all Oct 21, 2026)
No official fix8.1 and older (end-of-life). PHP published source-only backports for 8.1, 8.0, and 7.4.
ExploitationProofs of concept circulating, per CERT-EU; exploitation in the wild reported by watchTowr. Not in CISA's KEV catalog as of 3:45 PM CDT, October 21.
CVE recordsPublished on cve.org and analyzed by NVD, which adds its own CVSS v3.1 score of 9.8
CreditReported by Wiz, OpenAI, and Ryan at Calif.io; fixed by Arnaud Le Blanc, Ilija Tovilo, Jakub Zelenka, and Nora Dossche (per PHP's CVE records)

Who is affected

Any PHP that serves web requests is affected unless it runs the fixed build for its branch. The server API it runs under changes how exposed it is; that's covered further down.

BranchStatus on Oct 21, 2026Fixed inSecurity support until
8.5Active support8.5.12Dec 31, 2029
8.4Active support8.4.27Dec 31, 2028
8.3Security fixes only8.3.36Dec 31, 2027
8.2Security fixes only8.2.35Dec 31, 2026
8.1End-of-life (Dec 31, 2025)source backport only—
8.0End-of-life (Nov 26, 2023)source backport only—
7.4End-of-life (Nov 28, 2022)source backport only—
7.3 and olderEnd-of-lifenothing—

End-of-life branches are affected, back to PHP 5.4 at least. Wiz, one of the reporters, says every PHP version released in the last decade is affected by at least one of them, "going back to version 5.4," and Google Cloud's bulletin lists "all PHP versions between 5.4 and 8.5." CERT-EU lists "end-of-life branches (PHP 8.1 and older)" among the affected products, and NVD's records mark every version before 8.2.35 as vulnerable. The oldest releases may carry only CVE-2026-109619: Red Hat lists the PHP 5.3 and 5.4 in RHEL 6 and 7 as affected by it, but not by CVE-2026-109618. An appliance or legacy server still running PHP 5.x or 7.x should be treated as vulnerable. PHP 8.6 is still in release-candidate testing; the advisories cover only the stable branches.

PHP inside other products. PHP also runs inside appliances, network devices, management interfaces, and commercial software, often where you can't update it yourself. Those need the vendor's fix. CERT-EU recommends the NCSC-NL php2shell repository for identifying third-party software that embeds PHP.

How the vulnerabilities work

A PHP web server keeps a pool of long-lived worker processes, and each worker handles many requests in turn. Every request gets its own memory. When a request ends, PHP frees that memory and resets the worker for the next one. Both vulnerabilities break that cleanup:

  • CVE-2026-109618: when a request runs out of memory, PHP abandons it on the spot. If that happens while PHP is still setting the request up — parsing a file upload, for example — the cleanup treats half-built data as valid and corrupts memory.
  • CVE-2026-109619: when a request dies from a fatal error, some of the worker's internal state can keep pointing at memory that has already been freed. The next request on that worker uses it.

An attacker can trigger either bug with crafted HTTP requests and no login. On Apache's mod_php, PHP demonstrated the attack with an unauthenticated request that triggers it before any application code runs, so the application or framework you use doesn't change your exposure. PHP's team turned both bugs into working exploits: code execution with the privileges of the web server's account, which typically reaches everything that account can read — application code, configuration files, database credentials, and API keys.

CVE-2026-109619 can also leak memory without running any code. PHP lists memory disclosure among its confirmed impacts, and Wiz warns that worker memory "may contain passwords, authentication tokens, API keys and certificates belonging to other requests or the server itself."

One commit, "Avoid state corruption via bailout," fixes both, so a single update covers both CVEs.

CVE-2026-109618: out-of-memory corruption

PHP enforces memory_limit by aborting the request with a longjmp() the moment an allocation would exceed it. In a few places, request state is reachable but not fully initialized when that jump happens, and the failing allocation needn't be related to it. Request shutdown then reads, branches on, or frees the half-built state, and that memory may still hold attacker-controlled data from earlier allocations. PHP says an attacker can force the out-of-memory condition on demand with crafted multipart (file-upload) requests, and it demonstrated complete RCE over HTTP against mod_php with default input and memory limits.

The fix stops using longjmp() for out-of-memory. PHP now ends the request with a graceful "soft" bailout at a safe point, and keeps a hard exit at a higher threshold.

CVE-2026-109619: stale global state

Some state that belongs to the worker — error, session, object, and extension state — points into memory owned by the current request, and must be reset before that memory is freed. A fatal error (an uncaught error, Maximum execution time exceeded, or out-of-memory) can cut an operation short before its reset runs, or a late diagnostic can repopulate error state after it was cleared. Either way, the pointer outlives its memory, and the next request on the same worker reads it before initialization resets it: a use-after-free that a crafted heap layout turns into RCE.

Exploitation takes two requests on one worker: one that leaves stale state behind, and a later one that touches it early. PHP confirmed two such early operations: diagnostics raised while applying invalid or deprecated INI settings, and session upload progress, which is enabled by default and runs without your code ever calling session_start(). PHP 8.5's fatal-error backtraces are the strongest case and the basis of the confirmed mod_php RCE; the session-upload-progress path was validated against both mod_php and PHP-FPM.

Risk by server API (SAPI)

A server API, or SAPI, is the layer that connects PHP to whatever passes it web requests: a module inside Apache (mod_php), a pool of FastCGI workers behind nginx, Apache, or Caddy (PHP-FPM), a CGI binary (php-cgi), LiteSpeed's own PHP processes (LSAPI), or an application server with PHP built in (FrankenPHP). The SAPI controls how workers start, get reused, and clean up between requests — exactly where both bugs live — so it changes how exposed you are. The command-line php you run in a terminal or cron job is a SAPI too, but it doesn't serve web requests and isn't the concern here.

Every web SAPI needs the update. PHP's advisories rank the risk:

Server APICVE-2026-109618CVE-2026-109619
Apache mod_phpConfirmed RCEConfirmed RCE
PHP-FPMSuspectedConfirmed RCE, application-dependent
FrankenPHPLikelyNot shown in the default configuration
LiteSpeedLikelyConditional
php-cgiNamed at riskNamed at risk
  • mod_php is the worst case. It runs request shutdown unconditionally, so a request that fails during startup still reaches the vulnerable cleanup, "entirely before any application-specific code begins execution."
  • PHP-FPM is less proven, not safe. PHP calls it "susceptible" to CVE-2026-109618 by source analysis, without a complete exploit, and validated a working exploit for CVE-2026-109619 on a normal dynamic pool — one that "depends on a suitable application operation."
  • FrankenPHP also runs shutdown unconditionally, "analogous to Apache mod_php." PHP didn't show the second bug in its default configuration, but adds that "this does not make this environment immune." LiteSpeed "models FPM," with exploits for the first bug "likely but unvalidated," and is a conditional candidate for the second because it can apply special INI values early.

Red Hat rates both CVEs Important rather than Critical on RHEL. For CVE-2026-109618, it explains that standard RHEL deployments use PHP-FPM rather than mod_php, and "PHP-FPM workers exit on early initialization failures before reaching the corrupted structures, so remote code execution is difficult in practice and typically requires non-default behavior." Red Hat still describes FPM as reachable "through application-stage paths" for both bugs. A lower rating isn't a reason to wait.

How to check your systems

Check every place PHP runs, not just the host you're logged into. A machine can run a patched php on the command line while a container on it serves an old php:8.2-fpm image.

Check the PHP version and SAPI serving your site

Shell
1php -v                                     # the command-line PHP, not necessarily the web's23# The FPM binary's own version4php-fpm8.3 -v                              # Debian/Ubuntu (the name matches the branch)5php-fpm -v                                 # RHEL and most container images67# Is Apache running mod_php?8apache2ctl -M 2>/dev/null | grep -i php    # Debian/Ubuntu: "php_module" means mod_php9httpd -M 2>/dev/null | grep -i php         # RHEL and derivatives1011# Which PHP processes are running?12ps aux | grep -E 'php-fpm|lsphp|frankenphp|php-cgi' | grep -v grep

php -v and php -i describe the command-line build, which can differ from the one serving your site. The most reliable read of the web side is a temporary phpinfo() page: its "Server API" line says "Apache 2.0 Handler" for mod_php or "FPM/FastCGI" for FPM, next to the "PHP Version." Delete it as soon as you've read it — phpinfo() exposes the configuration details attackers look for. And php-fpm -v reads the binary on disk: workers started before an update keep running the old code until you restart them.

Check distribution packages

Shell
1# Debian / Ubuntu2dpkg -l | grep -E '^ii' | grep -E 'php|mod-php'3apt list --upgradable 2>/dev/null | grep -i php45# RHEL and derivatives, Fedora6rpm -qa | grep -E '^php'7dnf updateinfo list --cve CVE-2026-109618   # if the vendor ships CVE metadata

Then confirm against the distribution's security tracker:

PHP said distributions "received the patches in advance." Where they stood at 3:45 PM CDT:

  • Ubuntu had fixed both CVEs, at Critical priority, on every supported release, plus 20.04, 18.04, 16.04, and 14.04 — PHP 5.5 — through Ubuntu Pro.
  • Debian had fixed bookworm in 8.2.35-1~deb12u1 (DLA-4848-1) and trixie in 8.4.27-1~deb13u1 (DSA-6574-1); unstable was still unfixed. Debian 11 left LTS on August 31, 2026, and its php7.4 doesn't appear in Debian's tracker for these CVEs.
  • Red Hat had fixed RHEL 10, RHEL 9's base php and its php:8.2 and php:8.3 streams, and RHEL 8's php:7.4 stream. RHEL 9's php:8.4 and RHEL 8's php:8.2 streams were still listed as affected.

Third-party repositories differ:

  • Ondřej Surý's repositories — packages.sury.org for Debian 11, 12, and 13, and ppa:ondrej/php for Ubuntu 22.04 and 24.04 — published October 21 builds of every branch from 7.4 to 8.5. The 7.4 and 8.2 changelogs we checked cite both CVEs. For Debian 11 hosts, which Debian no longer covers, it was the only packaged fix we found.
  • rpms.remirepo.net, by PHP's account, "will not have updates today"; PHP urges its users to switch to distribution packages or build from source.

Check containers and Kubernetes

Shell
1# Local images and the version inside one2docker images --format '{{.Repository}}:{{.Tag}}  {{.ID}}  {{.CreatedSince}}' | grep -i php3docker run --rm --entrypoint php <image> -v45# Running containers6docker ps --format '{{.ID}}  {{.Image}}  {{.Names}}'7docker exec <container> php -v89# Kubernetes: every pod image, cluster-wide10kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{range .spec.containers[*]}{.image}{" "}{end}{"\n"}{end}' | grep -i php

A tag encodes the SAPI: php:8.2-apache is mod_php, php:8.2-fpm is FPM. Images that bundle PHP under another name (wordpress:…, for instance) won't match a php grep; check those with php -v inside the container.

The official php Docker images were updated on October 21. When we checked around 11:10 AM CDT, Docker Hub was serving 8.2.35, 8.3.36, 8.4.27, and 8.5.12, and the moving 8.2–8.5 and latest tags resolved to them (pushed around 10:40 AM CDT). Earlier that morning, the same tags still pointed at the vulnerable 8.2.34, 8.3.35, 8.4.26, and 8.5.11 builds, so anything pulled before then needs a fresh pull. Rebuild with docker build --pull; cached layers and digest-pinned images (php:8.2@sha256:…) won't update on their own.

Check repositories and CI pipelines

Shell
1# PHP base images in Dockerfiles and Containerfiles, any registry or variant2grep -rniE --exclude-dir=node_modules \3  --include='Dockerfile*' --include='Containerfile*' --include='*.dockerfile' \4  '^[[:space:]]*FROM[[:space:]].*php:' .56# CI pipelines, compose files, and setup-php actions7grep -rnE --exclude-dir=node_modules --include='*.yml' --include='*.yaml' --include='Dockerfile*' \8  'php:[0-9]|php-version|shivammathur/setup-php' .

We tested these patterns with GNU grep 3.8 against a fixture repo: they catch --platform and registry-prefixed FROM lines and shivammathur/setup-php pins, and skip node_modules.

How to fix

Update PHP and restart every worker

Install the release for your branch — 8.5.12, 8.4.27, 8.3.36, or 8.2.35 — or your distribution's fixed package. Then restart every PHP worker: a patched binary on disk does nothing until the running FPM pools and Apache processes are replaced.

Shell
1systemctl restart php8.3-fpm                  # FPM (the unit name matches your branch)2systemctl restart apache2                     # mod_php on Debian/Ubuntu (httpd on RHEL)3kubectl rollout restart deployment/<name>     # containers: roll the pods onto the new image

On 8.1, 8.0, or 7.4, get a backported package from your distribution or LTS vendor, or build from PHP's source backport (see end-of-life versions). Both are stopgaps; the real fix is moving to a supported branch.

Check for signs of compromise

The details leaked a day before the fixes shipped, so patching isn't the end of it. The FBI's Cyber Division asks organizations to "monitor web servers for suspicious activity, including PHP processes unexpectedly launching command shells or downloading files." A starting point:

Shell
1# Everything running as the web server's user: expect only php-fpm or apache2 workers2# (www-data on Debian/Ubuntu; apache, nginx, or the FPM pool's user elsewhere)3ps -u www-data -o pid,ppid,lstart,args45# Worker crashes since the leak: failed exploit attempts tend to crash workers6journalctl _TRANSPORT=kernel --since 2026-10-20 | grep -i segfault   # across reboots7grep -h SIGSEGV /var/log/php*-fpm.log /var/log/php-fpm/error.log 2>/dev/null8grep -h 'Segmentation fault' /var/log/apache2/error.log   # RHEL: httpd/error_log9docker logs <container> 2>&1 | grep -E 'SIGSEGV|Segmentation fault'   # containers1011# PHP files created or changed under the web root since the leak (adjust the path)12find /var/www -type f -name '*.php' -newermt 2026-10-20 -ls

A shell, curl, wget, or an unfamiliar binary running as the web user is a red flag, and so is a PHP file that no deploy explains. A clean result isn't proof of safety. If you find signs of compromise, the FBI asks you to "isolate affected systems, preserve your web server and PHP logs," and report it to your local FBI field office or IC3.

Rotate secrets even if the checks come back clean. CVE-2026-109619's memory disclosure doesn't start a shell or write a file, so nothing above would show it. For internet-facing servers that ran a vulnerable version, change the credentials their PHP processes held: database passwords, API keys, and session and signing secrets.

If you can't patch immediately

Take the system offline until you can patch it. The FBI's Cyber Division says: "If an immediate update is not feasible it is recommended that organizations take the system offline until it can be fully mitigated." CERT-EU advises "isolating internet-facing applications from public networks until a fix is applied and verified." It's disruptive, but it's a smaller incident than an attacker running code on your server.

If the system has to stay online, apply PHP's interim measures administratively — in php.ini, the FPM pool, or the server configuration, not ini_set() or .user.ini — and restart every worker.

For CVE-2026-109618 (out-of-memory corruption):

  • Set memory_limit=-1 administratively, and make sure nothing — pool, directory, or app — puts a finite limit back. This removes the controllable trigger, but an underlying allocation failure can still reach the bug. It also lets one request take as much memory as it can get, so pair it with the container or cgroup limit below.
  • Set a conservative post_max_size (8M if you don't accept uploads, 32M if you do), keep upload_max_filesize below it, and enforce request-size, field-count, part-count, header-count, and nesting limits at the proxy — including for requests with no usable Content-Length. If you don't use multipart forms, block them at the frontend.
  • Use a container or cgroup memory limit as an availability boundary, ideally one that kills only the affected worker. Do not use RLIMIT_AS or RLIMIT_DATA: they cause the exact allocation failure that triggers the bug.

For CVE-2026-109619 (stale global state):

  • Set session.upload_progress.enabled=0 and restart every worker. This blocks the confirmed session paths, not other variants; PHP suggests leaving it off after patching if you don't use it.
  • On PHP 8.5, set fatal_error_backtraces=0 and restart every worker. This blocks the confirmed fatal-backtrace path only.
  • Remove invalid or deprecated per-request INI settings that emit diagnostics before initialization. Hiding diagnostics with error_reporting, display_errors, or @ does not help. Fix attacker-reachable fatal errors and execution timeouts. If you can absorb the cost, pm.max_requests=1 recycles each FPM worker after a single request, which means starting a new process for every request.

End-of-life versions

PHP 8.1, 8.0, and 7.4 get no official release. Instead, "given the severity of these vulnerabilities," PHP's security team published minimal source-only backports for those three branches: single commits by Arnaud Le Blanc, dated October 18, on branches named for the CVEs. "Minimal" is literal. On the supported branches, the fix adds about 11,000 lines across roughly 400 files, nearly two-thirds of them tests; the backports add 230 to 310 lines across 17 to 23 files.

Avoid state corruption via bailout
php/php-src · Arnaud Le Blanc · Oct 18, 2026
8.5.1231c0ea7
423 files
11,556 lines added, 1,017 removed
8.4.27506e87f
402 files
11,112 lines added, 1,032 removed
8.3.363c832b5
392 files
10,833 lines added, 1,020 removed
8.2.3501a40e8
389 files
10,759 lines added, 988 removed
8.1 backport1d7dec1
23 files · branch PHP-8.1-CVE-2026-109618-109619
311 lines added, 73 removed
8.0 backport82f8f31
17 files · branch PHP-8.0-CVE-2026-109618-109619
229 lines added, 59 removed
7.4 backport712e60f
17 files · branch PHP-7.4-CVE-2026-109618-109619
240 lines added, 59 removed

The backports are unofficial, with no binaries and no ongoing support. Installing php8.1 from an old repository or pulling an old php:8.1-apache tag gets you none of it unless your vendor ships the fix. For 7.3 and older, PHP offers nothing.

PHP 8.2 reaches end-of-life on December 31, 2026. Patch to 8.2.35 now, then plan the move to 8.4 or 8.5, so you're not back here in ten weeks with no release to take.

Timeline and exploitation status

All times are CDT (UTC−5).

WhenWhat
Oct 20 · 11:39 AMKevin Beaumont reports that the two CVEs have leaked before the patch
Oct 20 · 1:26 PMwatchTowr confirms the leaked vulnerabilities are real; disclosure had been embargoed until Thursday, October 22
Oct 20PHP pre-announces a critical security release for October 21 at 9:00 AM CDT
Oct 21 · 3:31 AMThe earliest public GitHub repository we found presenting itself as a proof of concept is created
Oct 21 · 8:30 AMPHP releases 8.5.12, 8.4.27, 8.3.36, and 8.2.35, half an hour early
Oct 21 · 8:48–8:54 AMBoth CVE records published
Oct 21 · 9:59 AMThe FBI's Cyber Division posts a critical vulnerability alert: "Patch and Hunt Immediately"
Oct 21 · ~10:40 AMUpdated official php images pushed to Docker Hub
Oct 21CERT-EU publishes Security Advisory 2026-018

Exploitation. CERT-EU reports proofs of concept circulating, which "raises the likelihood that attackers are already exploiting the vulnerabilities." watchTowr's FAQ says its honeypot network has observed exploitation in the wild since October 21, and Cloudflare's CTO, Dane Knecht, said the company was "seeing early attacks emerging," per Tenable. CISA hadn't added either CVE to its KEV catalog as of 3:45 PM CDT. We haven't tested any public proof of concept, and we aren't linking them.

Updates to this post

We'll revise this post and mark it updated as the picture changes: Red Hat and Debian fixes for the remaining releases, CISA's KEV decision, and confirmed compromises.

Get help

If the hard part is the inventory — which hosts, containers, images, and CI pipelines run which PHP, on which SAPI — or you want a second set of eyes on the upgrade and the interim configuration, our advisors do exactly this.

Atlas Service
Atlas Technical Consulting
Senior advisors for security audits, code reviews, and DevOps work — a two-hour discovery block with no retainer commitment, and a 24-hour response SLA.

This is the second of two critical runtime disclosures we're covering from October 21. The other: a remote-code-execution bug in Node.js's Brotli decoder, with the same container-inventory problem underneath.

Sources

Atlas Security
Security Advisories

The Atlas security byline: write-ups of vulnerabilities in widely deployed software — what changed, who is exposed, and what to check — verified against primary sources.

Continue reading

More from the Atlas Meridian

Security
14 min read

Node.js's October 2026 Brotli Decoder RCE: CVE-2026-111497

Find every runtime exposed to CVE-2026-111497, a High-severity Node.js Brotli bug fixed in 22.23.4, 24.22.1, and 26.12.1 — and never on end-of-life lines.

Atlas Security
Security Advisories
View category
Product
15 min read

Why we built Foundry

A developer everything-app — omnibar, sandboxes, calc, HTTP client, todos, notes — built because no single tool did all of it under one hotkey.

Trevor Fannin
Founder and CEO, Atlas Industries
View category
Engage · Atlas Engineering

Reading is one thing. Shipping is another.

If this writeup resonates with what you're building, let's talk. We'll connect you directly with an engineer to assist.