PHP2Shell alert: critical PHP flaws CVE-2026-109618 / 109619 — check your servers and get patched fast
HashTech Systems
Cybersecurity

PHP2Shell (CVE-2026-109618, CVE-2026-109619): What It Is and How to Patch Every Server

A practical PHP2Shell guide: affected and fixed PHP versions, how to find every PHP runtime, patching per platform, workarounds and compromise checks.

HashTech Engineering · October 26, 2026 · 11 min read

On 21 October 2026 the PHP project shipped emergency releases for two critical flaws in the PHP engine itself, now widely called PHP2Shell. Both are rated 9.2 on CVSS v4.0, both can give an unauthenticated attacker code execution as the web server user, and both sit in code that runs before your application does. This guide covers what the bugs are, which versions are fixed, how to find every PHP runtime on a server, how to patch on the common platforms, what to do if you cannot patch today, and how to look for signs that someone got in first.

What PHP2Shell is, in plain words

When PHP receives a web request it parses the request body, including file uploads, into internal structures before your code runs. The researchers found two ways to leave those structures in a broken state that a later step trusts:

  • CVE-2026-109618 (out-of-memory corruption). If PHP runs out of memory part-way through setting up request data, cleanup can treat a half-built entry as valid. A request crafted to hit memory_limit at the right moment corrupts memory.
  • CVE-2026-109619 (stale global state). A PHP worker handles many requests in turn. A fatal error can interrupt the reset between requests, so state from one request (freed memory) is used by the next one on the same worker: a use-after-free. Confirmed paths include session upload progress and, on PHP 8.5 only, fatal error backtraces.

Every way PHP serves HTTP is in scope: PHP-FPM, Apache mod_php, php-cgi, LiteSpeed and FrankenPHP. PHP says the risk is highest with mod_php. The application does not need to call session_start() or use uploads for the request parsing to happen. The PHP CLI used by cron jobs is not reachable over HTTP, but it is often a different build from the one serving web traffic, which is why the inventory step below matters.

Is it being exploited?

Sources differ, so here is what each says. Amazon Threat Intelligence logged exploitation attempts against its honeypots from 17 October, four days before disclosure. watchTowr reports exploitation of both CVEs in the wild from 21 October. Cloudflare saw attempts climb into the millions by 22 October, and Sophos and Arctic Wolf reported attempts to drop a Mirai botnet variant. On the other side, Sansec found that the public proof-of-concept exploits do not work against a default PHP install, and Wordfence and others had not confirmed a successful compromise when reported on 23 October. CISA's 21 October alert said it had not observed successful exploitation, and the CVEs were not in CISA's Known Exploited Vulnerabilities catalog as of its 23 October update. The UK NCSC urged organisations to patch immediately.

Treat it as urgent anyway. Scanning is universal, exploit quality will improve, and if you start looking for compromise, start from 17 October, not the patch date.

Who is affected and what fixes it

PHP branchStatusWhat to run
8.5Fixed upstream8.5.12 or later
8.4Fixed upstream8.4.27 or later
8.3Fixed upstream8.3.36 or later
8.2Fixed upstream (branch ends 31 Dec 2026)8.2.35 or later
8.1, 8.0, 7.4End of life, no official releaseA patched distro or LTS vendor package, PHP's source backports, or an upgrade
7.3 and older, including PHP 5Affected, no upstream fixUpgrade, a vendor backport if one exists, or isolate the system

Step 1: find every PHP runtime on the box

The CLI, PHP-FPM and mod_php can be different versions, control panels install their own builds under /opt, and every container carries its own PHP. These checks only read, they change nothing.

bash
# PHP binaries and modules on the root filesystem (repeat for other mounts such as /opt)
sudo find / -xdev -type f \( -name 'php' -o -name 'php[0-9]*' -o -name 'php-fpm*' -o -name 'php-cgi*' \
  -o -name 'lsphp' -o -name 'frankenphp' -o -name 'libphp*.so' \) 2>/dev/null

# What is serving traffic right now
ps -eo pid,user,lstart,args | grep -E 'php|apache2|httpd|lsphp|frankenphp' | grep -v grep

# The actual binary behind each PHP-FPM master, then ask it for its version
for pid in $(pgrep -f 'php-fpm: master'); do sudo readlink /proc/$pid/exe; done

# Is Apache loading mod_php? (apache2ctl on Debian/Ubuntu)
sudo apachectl -M 2>/dev/null | grep -i php

# Installed packages
dpkg -l | grep -E '^ii +(php|libapache2-mod-php)'   # Debian/Ubuntu
rpm -qa 'php*' | sort                                 # RHEL family, Amazon Linux

# Containers
docker ps --format '{{.ID}}  {{.Image}}  {{.Names}}'
docker exec <container> php -v

Common panel locations: /opt/cpanel/ea-php*/root/usr/bin/php, /opt/plesk/php/*/bin/php, /opt/remi/php*/root/usr/bin/php and /usr/local/lsws/lsphp*/bin/php. Run each with -v. Do not leave a phpinfo() page on a public site to check; it tells attackers the same thing.

Step 2: patch, by platform

Ubuntu and Debian

Ubuntu fixed the archive packages in USN-8948-1 on 21 October: 22.04 (php8.1 8.1.2-1ubuntu2.28), 24.04 (php8.3 8.3.6-0ubuntu0.24.04.13), 26.04 (php8.5 8.5.4-0ubuntu1.5) and 26.10 (php8.5 8.5.9-0ubuntu2.1). Ubuntu Pro covers 14.04 to 20.04. Debian fixed trixie in DSA-6574-1 (php8.4 8.4.27-1~deb13u1) and bookworm in DLA-4848-1 (php8.2 8.2.35-1~deb12u1).

If you use Ondřej Surý's repository (ppa:ondrej/php or packages.sury.org), its 21 October builds include 8.3.36 and patched builds for older branches. Their changelogs list the two CVEs, but not always in the top entry, so search the whole changelog.

bash
# Check (read-only): is the fix in the installed package? Use your branch's package name
zgrep -E 'CVE-2026-10961(8|9)' /usr/share/doc/php8.3-common/changelog.Debian.gz

# Change: install updates
sudo apt update && sudo apt upgrade

RHEL, AlmaLinux and Rocky Linux

Red Hat's bulletin RHSB-2026-013 lists RHEL 7, 8, 9 and 10 as affected (RHEL 7 by CVE-2026-109619 only) and says fixes are being released in stages. Check the RHEL, AlmaLinux or Rocky errata for your PHP stream and confirm the advisory names the CVEs before you rely on it. If you use Remi's repository, Remi published 8.2.35, 8.3.36, 8.4.27 and 8.5.12 on 22 October in remi-modular, and as Software Collections (for example php83-php-* packages and the php83-php-fpm service) in remi-safe.

bash
# Check (read-only)
dnf module list --enabled php 2>/dev/null     # which stream is enabled (EL8/EL9)
rpm -q --changelog php-common | grep -E 'CVE-2026-10961(8|9)'

# Change: install updates
sudo dnf upgrade --refresh 'php*'

Amazon Linux

On Amazon Linux 2023, php8.2, php8.3, php8.4 and php8.5 are fixed (ALAS2023-2026-3301 to 3304, 22 October). php8.1 on AL2023 and the core php package on Amazon Linux 2 are marked No Fix Planned, so those need an upgrade to a newer stream. The AL2 php8.2 extra is fixed in ALAS2PHP8.2-2026-015. AL2023 pins instances to a release version; if dnf finds nothing, run dnf check-release-update to see whether you need a newer release.

bash
# Change: update your stream, e.g. php8.3
sudo dnf upgrade --refresh 'php8.3*'

Windows and IIS

windows.php.net has builds for 8.2.35, 8.3.36, 8.4.27 and 8.5.12. On 26 October these were rebuilt as -1 packages (for example 8.4.27-1) to pick up a separate Brotli fix, so download the latest. Nothing is published for 8.1 or older. Replace the PHP folder that IIS's FastCGI handler points to, keep your php.ini, then recycle the application pools or run iisreset. Check php-cgi.exe -v at the exact path IIS uses. Bundles like XAMPP and WampServer carry their own copy.

cPanel, Plesk and other control panels

Panels ship and update their own PHP builds, which are separate from the OS packages. Run the panel's update (WHM and EasyApache 4 for cPanel, Tools & Settings > Updates or plesk installer for Plesk). Check each installed version under /opt/cpanel or /opt/plesk/php, and confirm the panel's changelog names the CVEs. CloudLinux alt-php is updated separately. Plesk also runs its own PHP engine for the panel itself, so make sure that is covered too.

Docker and Kubernetes

Patched official php image tags (8.2.35, 8.3.36, 8.4.27, 8.5.12 in -fpm, -apache, -cli and other variants) were on Docker Hub by 24 October. The official 8.1 and older tags have not been updated. A running container keeps its old PHP until you rebuild and recreate it, and images that install PHP from distro packages need a rebuild too. Also check pinned digests, base images built by other teams, and third-party images such as WordPress.

bash
# Change: rebuild against fresh base images and recreate containers
docker compose build --pull
docker compose pull
docker compose up -d

# Verify inside the running service
docker compose exec <service> php -v

Step 3: restart workers and verify

Restart, do not just reload. Red Hat specifically advises a restart.

bash
# Debian/Ubuntu (match your version)
sudo systemctl restart php8.3-fpm
sudo systemctl restart apache2        # only if Apache uses mod_php

# RHEL family / Amazon Linux
sudo systemctl restart php-fpm
sudo systemctl restart httpd          # only if Apache uses mod_php

# Verify (read-only): start times should be after the update
ps -eo pid,lstart,args | grep -E 'php-fpm: master|apache2|httpd|lsphp' | grep -v grep
sudo needrestart -r l                 # Debian/Ubuntu, if installed
sudo dnf needs-restarting             # RHEL family

For LiteSpeed, restart the server and check that no old lsphp processes are still running. Then repeat the Step 1 inventory and confirm every runtime is on a fixed version or a package whose changelog lists both CVEs.

If you cannot patch today: temporary workarounds

PHP is clear that no configuration change makes an installation safe. These settings only reduce the risk while you patch:

  • session.upload_progress.enabled = 0 blocks the known CVE-2026-109619 path. On PHP 8.5 also set fatal_error_backtraces = 0.
  • memory_limit = -1 removes the allocation failure CVE-2026-109618 relies on. Use it only with a hard memory cap outside PHP (container limit or systemd MemoryMax=). Otherwise one request can use all the server's memory.
  • Keep request bodies small: post_max_size of 8M (32M if you need uploads), with upload_max_filesize below it, plus a matching limit in front of PHP (client_max_body_size in nginx, LimitRequestBody in Apache).
  • Do not cap memory with RLIMIT_AS or RLIMIT_DATA (for example systemd LimitAS=). That can cause exactly the allocation failure the bug needs.
  • If the application does not take uploads, consider blocking multipart/form-data at the proxy or WAF. Amazon also suggests this and has published AWS WAF guidance. Restrict internet access to anything you cannot patch.

Set these where requests cannot override them, before the request is parsed: php.ini, php_admin_flag / php_admin_value in the FPM pool, or php_admin_flag in Apache. Do not use .user.ini or ini_set(). Then restart the workers. For example, in a PHP-FPM pool file:

text
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[post_max_size] = 8M

Step 4: look for signs of compromise

A successful exploit may not crash anything or leave an error, so finding nothing proves nothing. Check from 17 October onward. These indicators come from Datadog Security Labs and Amazon:

  • Bursts of Allowed memory size of ... bytes exhausted ... in Unknown on line 0. "Unknown on line 0" means PHP died before any script ran. Normal heavy pages can also trigger it, so look for bursts from the same sources.
  • Apache AH00052: child pid ... exit signal Segmentation fault (11). A crash can mean an exploit attempt that guessed a memory address wrong.
  • Multipart requests with PHP_SESSION_UPLOAD_PROGRESS or PHPSESSID form fields your app does not use, deeply nested or very long field names, or upload filenames containing <?php or |O:. Standard access logs do not record request bodies, so check WAF or proxy logs.
  • The web server user (www-data, apache, nginx) starting sh, bash, curl or wget.
  • New or changed PHP files in web roots, unknown binaries in /tmp, /var/tmp or /dev/shm, new cron entries for the web user, and unexpected outbound connections.
bash
# All read-only. Adjust log paths and the web user for your system.
sudo zgrep -h 'Unknown on line 0' /var/log/php*fpm*.log* /var/log/apache2/error.log* /var/log/httpd/error_log* /var/log/nginx/error.log* 2>/dev/null | grep -c exhausted
sudo zgrep -h 'AH00052' /var/log/apache2/error.log* /var/log/httpd/error_log* 2>/dev/null | grep -i segmentation | tail

sudo find /var/www -type f -name '*.php' -newermt '2026-10-17' -ls     # expect your own deploys here too
sudo find /tmp /var/tmp /dev/shm -type f -newermt '2026-10-17' -ls
sudo crontab -u www-data -l
ps -u www-data -o pid,ppid,lstart,args --forest
sudo ss -tnp | grep -E 'php|apache2|httpd'

Amazon published source IPs from its honeypots, but warns they are shared anonymisation infrastructure. Use them to prioritise investigation, not as a blocklist.

If you find signs of compromise

  1. Isolate the host from the internet, or pull it out of the load balancer. Take a disk snapshot and keep the logs before you change anything.
  2. Do not just delete the web shell and move on. Assume the attacker ran code as the web user and read everything that user could read.
  3. Rotate every credential the server held: database passwords, API keys in .env and config files, SMTP credentials and cloud access keys. On AWS, review what the instance role can do and check CloudTrail for its use. See the AWS security baseline checklist.
  4. Rebuild from a known-good image or clean install, patch it, and redeploy application code from source control, not from the compromised disk.
  5. Check where else it could have reached: other servers that share credentials, and the database for new admin users.
  6. Work out whether personal data was exposed. In the UK, a reportable breach must go to the ICO within 72 hours of you becoming aware of it (UK GDPR obligations). US organisations should check state breach-notification rules and any contracts.

Sources

HashTech Systems offers a fixed-price PHP2Shell remediation service covering inventory, patching or backporting, worker restarts, verification and a compromise check.

Let's Talk

Ready to build something that lasts?

Whether it's a charging network, an AI rollout, or a core enterprise system — let's talk about what you're building.