Quick Answer
On 21 October 2026 the PHP project released PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 to fix two critical bugs, CVE-2026-109618 and CVE-2026-109619, that can let an attacker run code on your server without logging in. The advisory says they affect all PHP installations that serve web requests, and that updating is the only complete fix. PHP 8.1 and older get no new release from the PHP project.
What Happened, Day by Day
CISA's alert calls the pair "php2shell". Both bugs are rated 9.2 on CVSS v4.0, according to the php.net news archive. The timeline below uses only the PHP project, CISA and one security firm, and names which one said what.
| Date (2026) | What happened | Source |
|---|---|---|
| 20 October | PHP announces a critical security release for 21 October at 14:00 UTC, fixing two bugs rated CVSS v4.0 9.2 | php.net |
| 20 October | Details leak on social media before the planned disclosure date of 22 October | watchTowr |
| 21 October | PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 released | php.net |
| 21 October | CISA tells organisations to patch immediately and says it has not seen exploitation yet | CISA |
| 21 October | Exploitation seen in the wild through watchTowr's honeypot network | watchTowr |
| 22 October | Neither CVE is in CISA's Known Exploited Vulnerabilities catalog yet | watchTowr |
The CISA alert said on publication that it had not observed exploitation. The watchTowr FAQ, written by a security research firm, reports attacks against its honeypots from the same day. Both can be true: an alert is written at one moment, and attackers move fast once details are public.
Who Is at Risk
The PHP advisory lists PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. It considers the risk highest for mod_php, where it has a working exploit in which an unauthenticated request triggers the attack before any application code runs.
That last point matters for anyone who built an app with Cursor, Claude Code or any other AI tool. The bug is in PHP itself, not in your code. A tidy Laravel app, a WordPress site or a single PHP form is exposed in the same way if the PHP underneath it is an old version. Clean code does not help here. Only the PHP version does.
In plain terms, the two bugs are:
- CVE-2026-109618, "RCE via OOM corruption". When PHP runs out of memory at the wrong moment, request data can be left half set up, and the cleanup step then treats it as valid.
- CVE-2026-109619, "RCE via stale global state". Internal state from one request can survive after its memory is freed, and the next request handled by the same worker may use it.
Find the PHP Version Your Website Really Runs
The php -v command shows the command-line PHP. On a server with more than one PHP installed, the website can run a different one. The safest check is to ask the web server itself. Upload this file under a random name (not check.php), open it in your browser once, then delete it, because it shows your PHP version to anyone who finds it.
<?php
$fixed = ['8.6' => '8.6.0RC4', '8.5' => '8.5.12', '8.4' => '8.4.27', '8.3' => '8.3.36', '8.2' => '8.2.35'];
$branch = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;
if (!isset($fixed[$branch])) {
echo 'PHP ' . PHP_VERSION . ': no php.net release fixes this branch. Upgrade, or get a backport from your vendor.';
} elseif (version_compare(PHP_VERSION, $fixed[$branch], '<')) {
echo 'PHP ' . PHP_VERSION . ': vulnerable. Update to ' . $fixed[$branch] . ' or later.';
} else {
echo 'PHP ' . PHP_VERSION . ': has the 21 October 2026 fixes.';
}
This compares your version with php.net's numbers. The advisory says some distributions and LTS vendors provide backported fixes, and a backported build can keep an older version number. If your PHP comes from a Linux distribution or a vendor, their security notice is the final answer. PHP 8.6.0 RC4 also contains the fixes, but php.net says not to use it in production.
For Docker, check the image you actually deploy:
docker run --rm your-image php -v
How to Fix It
1. Update to a fixed release. This is the only step php.net calls a complete solution.
| Your PHP branch | Fixed version | Notes |
|---|---|---|
| 8.6 (release candidate) | 8.6.0 RC4 | php.net says not to use it in production |
| 8.5 | 8.5.12 | Supported |
| 8.4 | 8.4.27 | Supported |
| 8.3 | 8.3.36 | Supported |
| 8.2 | 8.2.35 | Reaches end of life on 31 December 2026 |
| 8.1 and older | No php.net release | Vendor backport, php.net's source backports for 7.4, 8.0 and 8.1, or upgrade |
2. Rebuild your Docker image. A container never updates its own PHP. It keeps the version that was in the base image on the day it was built.
# BAD: "latest" means whatever PHP existed when this image was last built
FROM php:latest
# BAD: 8.1 gets no fix from the PHP project
FROM php:8.1-apache
# GOOD: an exact, fixed version, listed in the official php image tags
FROM php:8.3.36-apache
docker build --pull --no-cache -t your-image .
docker run --rm your-image php -v
Our guide to pinning Docker image versions covers tags, digests and keeping pinned images up to date.
3. On shared or managed hosting, check the PHP version in your control panel and ask your host whether they have applied the update. The advisory says Linux distributions and LTS vendors received the patches in advance.
4. If you cannot update today, CISA says to take PHP systems offline until they are patched, and to do the same for PHP 8.1 or earlier. It adds that a web application firewall may give some protection until patching is done. The PHP advisory lists stopgaps that, in its words, "do not make an installation safe":
; php.ini stopgaps from the PHP advisory. They reduce exposure, they do not fix it.
session.upload_progress.enabled = 0
post_max_size = 8M
The advisory says to restart every worker after turning off upload progress, and to use post_max_size = 32M if your app needs file uploads, with upload_max_filesize kept below it. It also describes memory_limit=-1 set through php_admin_value, with caveats, so read the full advisory before you rely on it.
5. Hide your version number. With the default expose_php = 1, PHP announces its version in the X-Powered-By header, according to the PHP manual. Set expose_php = Off in php.ini. This tells attackers less. It fixes nothing.
Tools like VibeDoctor's Vibe Check (vibedoctor.io) flag Dockerfiles that use the :latest tag, and warn when your live site's X-Powered-By header shows a software version. They cannot see a PHP version your server hides, so the version check above is still the step that matters. Free to sign up.
6. Look for signs of attack. CISA suggests watching for PHP worker processes that start shells or download tools.
FAQ
Is my WordPress site affected?
WordPress runs on PHP, and the PHP advisory covers all PHP installations that serve web requests. What decides it is the PHP version on your server, not your WordPress version or plugins. Check it in your hosting panel or with the script above, and update PHP to a fixed release.
My app runs on PHP 8.1. What should I do?
The PHP project no longer ships releases for 8.1 and older. Its advisory gives three paths: a backported fix from your distribution or LTS vendor, the minimal source backports php.net published for 7.4, 8.0 and 8.1, or an upgrade to a supported branch. CISA says to keep such systems offline until they are patched or upgraded.
Are attackers already using PHP2Shell?
CISA said on 21 October that it had not observed exploitation at the time it published. watchTowr reports exploitation against its honeypots from 21 October. As of 22 October, watchTowr says neither CVE was in CISA's Known Exploited Vulnerabilities catalog.
Will a web application firewall protect me?
Only partly. CISA says a web application firewall may give some protection until patching is complete. It is a stopgap. The PHP advisory says only an update is a complete solution.
Does hiding the PHP version make me safe?
No. Setting expose_php = Off removes the version from the X-Powered-By header, so attackers learn less about your server. The vulnerable code is still there until you update PHP.