Security advisory · 22 October 2026

PHP2Shell: two critical RCEs in PHP itself — CVE-2026-109618 CVE-2026-109619

On 21 October 2026 the PHP team shipped emergency releases fixing two memory-safety bugs in the PHP engine. They allow unauthenticated remote code execution — the application on top does not have to be broken. Every PHP release back to 5.4 is affected by at least one of them. If you run a PHP site, patch it and restart the workers. That is the whole message; the rest of this page is how.

CVSS v4.0 9.2 critical · both NVD v3.1 9.8 Exploitation attempts observed Fixed: 8.5.12 · 8.4.27 · 8.3.36 · 8.2.35 No authentication required

01 Do this now

In order. Steps 1–3 are the ones that stop exploitation.

1
Find every PHP binary that serves traffic

Not just php -v. PHP is also inside containers, control panels (cPanel/EA, Plesk, CloudLinux alt-php, DirectAdmin), vendor appliances, Windows apps that ship php-cgi.exe, and CI images. Check the SAPI that actually answers requests — FPM, mod_php, php-cgi, FrankenPHP or LiteSpeed.

2
Update to the fixed release for your branch

8.5.12 · 8.4.27 · 8.3.36 · 8.2.35 — or your distro's backported package with the same CVE in its changelog. Fix internet-facing hosts first.

3
Restart every PHP worker

This is the step people skip. Installing the package replaces the file on disk; the old code is still in memory until FPM children / Apache workers are recycled. A patched package with un-restarted workers is still a vulnerable server.

4
Turn off session upload progress, even after patching

PHP's own advice: this feature is rarely used and barely tested, and it is the best-documented path into bug #2. session.upload_progress.enabled=0.

5
Cannot patch before the weekend?

Then take the app off the public internet or put it behind a VPN/WAF — CERT-EU and the NSA both recommend isolation for anything that can't be updated immediately. Configuration tweaks below reduce exposure but do not make a server safe.

There is no configuration that fully mitigates this

Both PHP advisories say it in capitals-of-intent: updating is the only complete mitigation. Every ini setting discussed later closes a specific demonstrated path. A server with all of them applied is still a server with a use-after-free in its request engine.

02 Am I affected?

If your PHP version is in the left column, yes — regardless of what the application does.

PHP branchVulnerableFixed inNotes
8.5< 8.5.128.5.12Also set fatal_error_backtraces=0 if unpatched — the confirmed mod_php exploit uses it.
8.4< 8.4.278.4.27Current stable. Upgrade.
8.3< 8.3.368.3.36Upgrade.
8.2< 8.2.358.2.35EOL 31 Dec 2026. Patch now, plan the move.
8.1 / 8.0 / 7.4allsource backports onlyNo official release. Minimal backports on php-src branches for people building from source, or use your distro/LTS vendor's package.
5.4 – 7.3allnoneNo fix from the PHP project. Upgrade, or rely on a vendor that backports (often for a fee).

Risk by server setup

Both bugs are in the engine, so the SAPI — not your framework — decides how easy this is.

SAPIStatus per PHP's advisoryWhat it means
Apache mod_php Demonstrated RCE Highest risk. A single unauthenticated request can trigger it before any application code runs. No app-level control helps.
PHP-FPM Susceptible; partial exploit shown FPM kills the child when request startup fails, which blocks one path. The session-upload-progress path was validated against FPM and depends on a suitable operation in your app.
FrankenPHP Likely susceptible Like mod_php it runs shutdown unconditionally — application-independent attacks are likely.
LSAPI / LiteSpeed Likely, unvalidated Models FPM behavior; application-specific exploits likely.
php-cgi Affected Named explicitly in the PHP advisory as at-risk.
CLI only e.g. cron scripts Not the attack surface described Both bugs are reached through HTTP request handling. A box running PHP only from cron isn't exposed the same way — but it will be the moment it serves a request.
The application does not matter

Wiz Research demonstrated remote code execution without authentication against stock WordPress, Drupal and Joomla containers — and stated that a plain "Hello World" PHP script on an affected version is vulnerable. Updating WordPress, Laravel, Drupal, a theme or a plugin does nothing for this. composer update does nothing for this. The bug is below your code.

Memory disclosure is a separate, quieter problem

Both issues can leak process memory — passwords, session tokens, API keys and TLS certificates belonging to other requests on the same worker — without ever achieving code execution. A box that shows no shell still may have leaked credentials.

03 What actually broke

Both are memory-safety bugs in parts of PHP every request touches: memory management and error handling.

CVE-2026-109618 — RCE via OOM corruption

PHP enforces your memory_limit by calling longjmp(): a non-local jump that abandons the request wherever it happens to be. In some contexts PHP has already made request memory reachable before fully initialising it. If an allocation then fails, that early exit is not accounted for and the request memory is left in an invalid state. Shutdown then reads or branches on it — and the failed allocation doesn't even have to be related to that memory.

Three multipart-parsing quirks let an attacker reach OOM while staying inside the apparent limits:

  • A multipart request without a usable Content-Length can pass the initial post_max_size check and keep sending decoded body data.
  • A multipart part can carry an unlimited number of headers, and PHP's in-memory representation of them costs far more than their wire size.
  • Empty file controls don't count toward max_file_uploads but still allocate metadata arrays; nested field names multiply that work.

The fix removes longjmp() for OOM entirely: a graceful "soft OOM" is deferred to the next VM safe point, and a hard _exit() fires above a second, higher threshold. Shutdown never sees invalid state.

CVE-2026-109619 — RCE via stale global state

A PHP worker handles requests one after another. Some global state (error, session, object and extension state) lives in the worker but points at memory owned by the request that created it. That state has to be reset before the request's memory is released. When a fatal error or OOM abandons an operation before it performs its matching reset, the heap is freed while the worker still references it — a use-after-free.

Exploiting it needs two halves in two requests on the same worker:

  • Producer — an operation that publishes request-owned state globally and then dies: parse/compile failure, uncaught error, failed require, Maximum execution time exceeded, or OOM.
  • Consumer — an operation in the next request that touches that state before normal initialisation overwrites it.

Two consumers are confirmed:

  • INI diagnostics during startup. An invalid or deprecated setting warning is raised before PHP decides whether to display or log it — so error_reporting, display_errors and the @ operator give you zero protection. With mod_php this is reachable through .htaccess and php_value/php_admin_*; with FPM, through PHP_VALUE/PHP_ADMIN_VALUE passed by nginx or mod_proxy_fcgi — which is exactly what many hosting panels do for every site.
  • Session upload progress. It reaches session handling before ordinary session initialisation, so it can consume session state left by an interrupted request. Enabled by default, and it needs no session_start() call from your app.
The single strongest confirmed case

On PHP 8.5 with fatal_error_backtraces enabled, fatal-error reporting stores a request-owned backtrace that shutdown never resets. That is the basis of the confirmed mod_php exploit. If you are on 8.5 and cannot patch immediately, this is the first knob to turn off.

04 Timeline — why this landed a day early

When (UTC)What happened
20 OctA Hacker News post claims two PHP RCEs rated CVSS 10.0 with the two CVE IDs, scheduled for 22 October disclosure. The poster admits "source: trust me, bro". The post is later deleted.
20 OctwatchTowr and other researchers confirm the bugs are real. PHP publishes an advance notice: two critical vulnerabilities, CVSS v4.0 9.2, release scheduled 21 Oct 14:00 UTC — reserving the right to ship early if details go public.
21 Oct ~13:30PHP releases 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Advisories published ~13:34; CVE records ~13:48.
21 OctCERT-EU publishes advisory 2026-018. The US NSA issues a short statement advising organisations that cannot update immediately to take affected systems offline.
21 Oct ~14:19watchTowr reports observing active exploitation attempts against both CVEs. Cloudflare reports attack traffic and attackers mutating payloads around its WAF rules, which it enabled by default before the patch. Hadrian reports attempts at scale via the session upload-progress path.
22 OctNo confirmed successful compromise of a specific server has been publicly reported. Proofs of concept are circulating; assume exploitation continues and improves.
Two numbers, one bug

The leaked "CVSS 10.0" was never PHP's score. PHP and NVD's v4.0 score is 9.2. NVD also publishes a v3.1 score of 9.8; Red Hat rates it 8.1 / Important because its default deployments use FPM rather than mod_php. The high attack-complexity component in the v4.0 vector (AC:H) is what separates 9.2 from 10 — exploitation needs precise heap shaping, not just a request. That lowers reliability per attempt; it does not lower the need to patch, because attempts can simply be repeated.

Not yet in CISA KEV

As of KEV catalog version 2026.10.21 (2026-10-21T14:04Z), neither CVE is listed. That is a statement about the catalog's update cycle, not about safety — active attempts were already being observed within an hour of release.

05 Patch runbooks by platform

Check your actual version first, then run the block that matches your host.

# The version serving traffic is what matters, not the CLI one.
php -v
php-fpm -v 2>/dev/null; php-fpm8.4 -v 2>/dev/null
apache2ctl -M 2>/dev/null | grep -i php        # mod_php present?
ps aux | grep -E 'php-fpm|php-cgi|lsphp|frankenphp' | grep -v grep

# And directly from a served page (most reliable):
#   echo '<?php echo PHP_VERSION;' > /var/www/html/_v.php

Debian 12 (bookworm) and Debian 13 (trixie)

sudo apt update
sudo apt list --upgradable 2>/dev/null | grep -i php
sudo apt install --only-upgrade php8.2-*        # bookworm
sudo apt install --only-upgrade php8.4-*        # trixie
# or simply:
sudo apt full-upgrade -y

sudo systemctl restart php8.2-fpm    # or php8.4-fpm
sudo systemctl restart apache2       # if using mod_php

Fixed packages: php8.4 8.4.27-1~deb13u1 (DSA-6574-1, trixie) and php8.2 8.2.35-1~deb12u1 (DLA-4848-1, bookworm). At time of writing, Debian's forky/sid were still marked unfixed — if you track unstable, check the tracker before assuming your version is clean.

Ubuntu 22.04 / 24.04 / 26.04 LTS / 26.10

sudo apt update
sudo apt install --only-upgrade 'php8.3-*'      # noble 24.04
sudo apt install --only-upgrade 'php8.1-*'      # jammy 22.04
sudo systemctl restart php8.3-fpm && sudo systemctl reload apache2

Ubuntu published USN-8948-1 and USN-8948-2 on 21 October. Fixed builds include php8.3 8.3.6-0ubuntu0.24.04.13 (noble), php8.1 8.1.2-1ubuntu2.28 (jammy), and php8.5 on 26.04 LTS (8.5.4-0ubuntu1.5) and 26.10 (8.5.9-0ubuntu2.1). Older releases (20.04 and earlier) are fixed through Extended Security Maintenance — Ubuntu Pro only.

RHEL 9 / 10, AlmaLinux, Rocky, CentOS Stream

sudo dnf check-update --security
sudo dnf upgrade-minimal --security -y
sudo dnf update php\* -y

sudo systemctl restart php-fpm
sudo systemctl restart httpd        # mod_php

Red Hat errata published 21 October:

  • RHEL 10 — RHSA-2026:87070 (php), RHSA-2026:87071 (php8.4)
  • RHEL 9 — RHSA-2026:87072 (php:8.2), RHSA-2026:87079 (php:8.3), RHSA-2026:87151 (php)
  • Red Hat Hardened Images — RHSA-2026:87414
Remi's RPM repository had no updates on release day

The PHP advisory says so explicitly: if you depend on rpms.remirepo.net, switch to distribution packages or build from source so you can apply the update immediately. Don't wait on a third-party repo for this one.

Alpine Linux

apk update && apk upgrade -U
apk policy php84 php83 | grep -E '^php|version'
rc-service php-fpm84 restart 2>/dev/null || service php-fpm84 restart

Verify against Alpine's secdb for your release — at the time this page was written I could not find CVE entries for either ID in the main or community trackers, so do not treat "no entry" as "not affected". Confirm the installed php8x version is at or above the upstream fixed release for that branch.

Docker / containers

Docker Hub overwrote the official php image tags with patched builds at release time. Rebuilding on the same mutable tag is not enough — a running container keeps the old layers until you pull and recreate.

docker pull php:8.4-fpm
docker compose build --pull --no-cache
docker compose up -d --force-recreate

# verify inside the running container, not on the host
docker compose exec -T app php -v | head -1

# bake the mitigation into the image rather than `docker exec`-ing it
# Dockerfile:
#   RUN printf 'session.upload_progress.enabled=Off\nfatal_error_backtraces=Off\n' \
#       > /usr/local/etc/php/conf.d/zz-php2shell.ini

Also fix the PHP version pinned in composer.json (config.platform.php), any .php-version / .tool-versions file, and the version passed to setup-php in CI — those pins rebuild the vulnerable runtime on the next deploy.

cPanel / WHM and CloudLinux

Multi-PHP boxes are the trap here: ea-php74, ea-php81, ea-php82, ea-php83, ea-php84 and CloudLinux alt-php* are separate packages, and a fix for one does not fix the others. Update through WHM, then verify package-by-package by changelog rather than by version string — cPanel often keeps the upstream version number and backports the patch.

# cPanel-provided update path
/scripts/upcp --force

# Verify per package, by changelog — not by version number
for p in $(rpm -qa 'ea-php*-php-common' 'alt-php*-common' | sort); do
  printf '%-56s ' "$p"
  rpm -q --changelog "$p" | head -30 | grep -q 'CVE-2026-109619' && echo FIX || echo 'NO FIX'
done

# Recycle every ea-php-fpm service that is running
for s in $(systemctl list-units --type=service --state=running --no-legend \
          | awk '/ea-php.*fpm/{print $1}'); do
  systemctl restart "$s"
done

Plesk

plesk installer update
# then restart the handlers you actually use
systemctl restart plesk-php*-fpm 2>/dev/null || true
systemctl restart sw-engine psa 2>/dev/null || true

Plesk keeps its own PHP builds under /opt/plesk/php/*, each with its own php.ini — check every version you have installed, not just the default.

Windows

Download the fixed Windows binaries from the PHP downloads page and replace the install directory, then restart the service hosting it (IIS via FastCGI, Apache, or whatever runs php-cgi.exe). Remember that desktop apps and appliances ship their own private php.exe — those need the vendor's update.

php -v
# IIS: restart the app pool / w3wp, not just the PHP folder
iisreset /restart

From source

./configure <your existing flags>
make -j"$(nproc)"
sudo make install
sudo systemctl restart php-fpm

For 7.4 / 8.0 / 8.1 the PHP team published minimal backports rather than releases: PHP-7.4-CVE-2026-109618-109619, PHP-8.0-…, PHP-8.1-…. These exist to keep you off the internet while you plan a real upgrade — 8.1 is unsupported and receives nothing else.

06 Verify the fix actually took

A green package version is not proof. Three checks, in increasing strength.

1 — The CLI reports the fixed version

php -v | head -1
# expect: PHP 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 (or a distro build with the CVE in its changelog)

# distro packages often keep the upstream number — check the changelog instead:
dpkg -s php8.3-fpm | grep ^Version
apt-get changelog php8.3-fpm 2>/dev/null | grep -m2 'CVE-2026-1096'
rpm -q --changelog php-fpm | grep -m2 'CVE-2026-1096'

2 — The SAPI that serves traffic reports it too

php-fpm -i 2>/dev/null | grep -m1 'PHP Version'
# and the CLI-vs-FPM mismatch that fools people:
sudo ls -l /proc/$(pgrep -o -f 'php-fpm: pool')/exe

On multiversion boxes the CLI, FPM, and mod_php can be three different builds. The only version that matters is the one answering HTTP.

3 — The running workers are using the new binary

Installing a package replaces the file on disk. Processes keep executing the old code from memory until they're recycled — php -v will happily print the new version while the vulnerable engine is still serving requests. Compare each worker's start time against the binary's mtime:

for pid in $(pgrep -f 'php-fpm|apache2|httpd|php-cgi'); do
  exe=$(readlink -f /proc/$pid/exe 2>/dev/null) || continue
  started=$(ps -o lstart= -p "$pid" 2>/dev/null)
  newer=$(find "$exe" -newermt "$started" 2>/dev/null)
  [ -n "$newer" ] && echo "STALE $pid  $exe  started:$started"
done
# no output = every worker is running a binary newer than its start time
Then make one live request

Serve a temp file that prints PHP_VERSION and the two relevant ini values, confirm the numbers, then delete it. That's the only check that proves what your visitors are getting.

php -i | grep -E 'session.upload_progress.enabled|fatal_error_backtraces'

Note that php -i from the CLI shows CLI ini, which can differ from FPM pool php_admin_value and from .htaccess/php_value in Apache. Check per-pool if you have several.

07 If you cannot patch today

These reduce exposure to specific demonstrated paths. None of them makes a server safe, and PHP says so in both advisories.

For CVE-2026-109618 (OOM corruption)

Remove the predictable memory-limit failure the exploit steers into:

# php.ini — and make sure nothing below can put a finite limit back
memory_limit = -1

# Prefer an admin-scoped setting the app can't override:
# FPM pool (php_admin_value, NOT php_value)
php_admin_value[memory_limit] = -1
# Apache
php_admin_value memory_limit -1
  • Bound request size independently of PHP. post_max_size = 8M if the app takes no uploads, 32M if it does, with upload_max_filesize below it.
  • Enforce limits at the proxy too — decoded request size, field count, multipart part count, header count, nesting depth — and make sure those limits cover requests with no usable Content-Length. That last clause is the one most configs miss.
  • Block multipart entirely at the frontend for apps that never accept file uploads.
  • Use a container/cgroup memory.max as an availability boundary, ideally killing only the affected worker.
  • Do not use RLIMIT_AS or RLIMIT_DATA as a substitute. When the limit is hit, mmap() fails and PHP takes the vulnerable longjmp() path — you'd be recreating the bug on purpose.

For CVE-2026-109619 (stale global state)

; /etc/php/8.5/fpm/conf.d/99-php2shell.ini  (restart every worker after)
session.upload_progress.enabled = 0
fatal_error_backtraces = 0        ; PHP 8.5 only — confirmed mod_php exploit path

; verify the FPM pools actually picked it up:
php-fpm -i 2>/dev/null | grep -E 'upload_progress.enabled|fatal_error_backtraces'
  • Put it in php.ini, an FPM pool or server config that applies before request parsing. ini_set() and .user.ini are too late and do nothing here.
  • Restart every worker after changing it. A config file edit alone changes nothing in a running pool.
  • Remove invalid or deprecated per-request INI overrides — .htaccess php_value, Apache php_admin_*, nginx PHP_VALUE/PHP_ADMIN_VALUE — because a warning raised while applying them is the confirmed consumer. This is common on panels like CloudPanel, which send fastcgi_param PHP_VALUE with memory_limit, post_max_size and date.timezone to every site.
  • Fix attacker-reachable fatal errors and timeouts — in callbacks, upload/import processing, destructors, serialization, output handlers and cleanup. Every reachable fatal is a potential producer.
  • Blunt instrument: pm.max_requests = 1 makes each worker handle one request then exit, which breaks the producer/consumer pairing. Costs performance; worth it on a small critical host while you stage the upgrade.
The isolation route

Both CERT-EU and the NSA recommend removing the exposure instead of tuning it: put the application behind a VPN or an IP allowlist, or take it offline until patched. For an internal tool that no stranger needs to reach, that's often faster and more honest than a stack of ini workarounds that only close the paths researchers have published.

08 Detect exploitation attempts

You will not find these in an application log — the attack completes before your code runs.

What to hunt for

  • Unexpected children of PHP processes. php-fpm, apache2 or php-cgi spawning sh, bash, nc, curl, wget, python or perl is the loudest signal there is.
  • Reverse-shell shapes in command lines: /dev/tcp/, mkfifo, fsockopen, bash -i.
  • Multipart requests without a usable Content-Length, or with an absurd number of part headers — the published OOM approach.
  • PHP_SESSION_UPLOAD_PROGRESS in request bodies where your app has no upload form.
  • New files in web roots, modified .htaccess, new cron jobs, new local users, outbound connections from the web tier.
# Quick process-tree triage — anything hanging off a PHP worker that isn't a socket deserves a look
ps -eo pid,ppid,user,etime,cmd --forest | grep -A3 -E 'php-fpm|php-cgi|apache2|httpd' | head -40

# Reverse-shell patterns in current command lines
ps auxww | grep -E '/dev/tcp/|mkfifo|nc -e|bash -i' | grep -v grep

# Web-root drift (tune to your tree)
find /var/www -type f -newermt '-7 days' -print 2>/dev/null | head -50

For ongoing monitoring, Florian Roth's process-watcher profile for this event logs every program a PHP process starts, with its command line. It records after the fact and prevents nothing — which is exactly right for a detector, but means it must already be running before an attacker arrives.

Memory disclosure leaves no shell

If both bugs can leak process memory, a quiet hit looks like "nothing happened" — plus credentials that later appear somewhere else. If you were unpatched and exposed, rotate the secrets that were reachable from that worker regardless of whether you find a shell: database passwords, API keys, session signing keys, and TLS private keys.

09 If you think you were hit

1
Isolate, don't reboot

Pull it from the network or firewall it. Rebooting destroys volatile evidence — process trees and /proc contents are exactly what you need.

2
Capture state before anything else

Preserve web server logs, PHP-FPM logs, auth logs, ps output and /proc/<pid>/* for the PHP workers, plus a file listing of web roots.

3
Look for persistence

Web shells (obfuscated files, eval/base64_decode chains), new cron entries, systemd units, SSH authorized_keys, new local accounts, and any change to .htaccess.

4
Rebuild from a known-good image

For memory-corruption RCE, "clean up the shell we found" is not a recovery strategy. Rebuild on a patched runtime, restore data deliberately, then rotate every credential the host could reach.

5
Report it

If it's a customer-facing incident, check your breach-notification obligations — GDPR, state laws, or contract language. If you're in the EU, CERT-EU's advisory is the reference your regulator will recognise.

10 Stuck on an EOL branch

This is the uncomfortable section. Most of the affected installs are not on 8.4.

BranchStatusRealistic options
8.2Supported until 31 Dec 2026Apply 8.2.35 today. Then treat the upgrade as a Q1 project — after December there are no more fixes at all.
8.1 / 8.0 / 7.4EOL; source backports publishedVendor backport (Debian/Ubuntu ESM, RHEL ELS), build from the published backport branch, or upgrade. There will be no 7.4.34 release.
5.4 – 7.3EOL; no project fixUpgrade. Failing that: isolate from the internet, or pay an LTS vendor that still backports (and confirm they shipped this one).
Shared hosting and managed panels

You cannot patch these yourself, so make the provider answer a specific question: which PHP branches did you deploy the CVE-2026-109618 / -109619 fix to, and when were the workers restarted? "We're on it" is not an answer. Ask for the branch list and the restart time, in writing. If your plan lets you select a PHP version in the panel, check that every version you can select has been fixed.

While you're making that call, remember the underlying point: an EOL PHP branch does not just lack this one fix, it lacks all of them. This event is the argument for budgeting the upgrade, not just a reason to apply a workaround.

11 FAQ

I updated WordPress / my plugins / ran composer update. Am I fine?

No. The vulnerabilities are in the PHP runtime, below any application code. Updating the app changes nothing about this. Check php -v on the server.

I'm behind a WAF — am I covered?

Partly, temporarily, and not reliably. Cloudflare turned rules on before the patch and still reported attackers mutating payloads to get around them. A WAF buys time to patch; it isn't a substitute, and it does nothing for an attacker already inside the network.

Does session.upload_progress.enabled=0 fix it?

No. It closes the confirmed session path for bug #2 and it is worth doing permanently, but PHP is explicit that other producers and consumers exist and that no configuration is a complete mitigation.

Is it being exploited in the wild?

Active exploitation attempts were observed from roughly 14:19 UTC on 21 October — watchTowr, Cloudflare, Hadrian, Patchstack and Vega all reported them, and Hadrian described at-scale attempts via the session upload-progress path. No publicly confirmed successful compromise of a named server as of this writing. "Attempts, not yet confirmed successes" is not a reason to schedule the patch for next week; the reliability of these chains improves with iteration.

Is it in CISA KEV?

Not as of catalog 2026.10.21 (released 21 October 14:04 UTC). Check the live catalog before relying on that.

We're on Windows / IIS. Same story?

Same bug, different packaging. Fixed Windows binaries are on php.net; the risk profile depends on whether you run FastCGI (FPM-like) or something mod_php-like. Replace the binaries and restart the app pool — and check any bundled php.exe shipped inside a vendor application separately.

How do I know the patch is actually live?

Two things: the binary version, and that the workers were restarted after the package landed. Section 6 has the loop that flags workers still running a replaced binary. A patched disk with stale workers is still a vulnerable server.

Where can I follow this?

The PHP advisory is the source of truth and gets updated. watchTowr and CERT-EU are the fastest secondary sources. Avoid copy-pasting exploits from "PoC" repos onto anything you don't own — and if you're testing, test against a local container.

12 Primary sources

Everything above is drawn from these. If any of them disagrees with me, they win.

  1. PHP security advisory — critical RCE vulnerabilities, update now (php.net, 21 Oct 2026)
  2. GHSA-w8hw-w9fx-j79w — RCE via OOM corruption (php-src advisory)
  3. GHSA-6wmf-4rv5-p3rp — RCE via stale global state (php-src advisory)
  4. NVD — CVE-2026-109618 · CVE-2026-109619 (CVSS v4.0 9.2 / v3.1 9.8)
  5. CERT-EU Security Advisory 2026-018 — Critical Vulnerabilities in PHP (21 Oct 2026)
  6. Wiz Research — PHP2Shell: AI uncovers critical RCE vulnerabilities affecting 70% of the Internet
  7. watchTowr — CVE-2026-109618 FAQ · php2shell exploitation update
  8. Debian security tracker — DSA-6574-1, DLA-4848-1
  9. Ubuntu CVE tracker — USN-8948-1, USN-8948-2
  10. Red Hat CVE-2026-109618 — RHSA-2026:87070 / 87071 / 87072 / 87079 / 87151, RHSA-2026:87414
  11. CISA Known Exploited Vulnerabilities catalog — checked, not listed as of 2026.10.21
  12. The PHP Foundation — today's PHP security release