On 21 October 2026, the PHP project shipped emergency releases for every supported branch (8.5.12, 8.4.27, 8.3.36 and 8.2.35) to close two vulnerabilities now known together as PHP2Shell: CVE-2026-109618 and CVE-2026-109619. Both are rated 9.2 out of 10 (CVSS v4.0). Both can let an attacker run code on your server without logging in.
The release was meant to go out a day later. Details leaked, the date was brought forward, and attackers did not wait for either: the first exploitation attempts were recorded four days before the patches existed.
This is not a bug in a plugin or a framework. It is in PHP itself, the runtime under WordPress, Drupal, Joomla, Magento, Laravel, Symfony and every custom PHP application. If a server answers web requests with PHP, it is in scope until proven otherwise.
Below: what the flaws are, who is exposed, how to check your real patch level (the version number most people look at will mislead you), how to fix it, and what to do if you cannot patch today.
What PHP2Shell Actually Is
A PHP worker does not live for a single request. Whether it is a PHP-FPM process or an Apache child running mod_php, the same worker handles one request after another and cleans up its internal state in between. PHP2Shell is two different ways of breaking that clean-up.
- CVE-2026-109618, memory exhaustion mid-request. If PHP runs out of memory at the wrong moment, it can be interrupted while internal request data is only partially initialised. The clean-up that follows then treats that half-built data as valid.
- CVE-2026-109619, stale state between requests. Internal state that belongs to one request can survive after its memory has been freed. The next request handled by the same worker may use that stale state before normal initialisation resets it.
Either way, PHP ends up trusting memory it should no longer trust, and an attacker who controls the requests can turn that into remote code execution with the permissions of the PHP process: enough to read the database credentials in your configuration files, drop a web shell, and move on from there.
The worst case is Apache with mod_php. There, a demonstrated exploit fires before any application code runs, which means your login page, your security plugin and every check inside the application never get to see the request.
Who Is Exposed
Every PHP installation that serves web requests:
- PHP-FPM behind Nginx, Apache or any other web server
- Apache with mod_php, where the risk is highest
- php-cgi, FrankenPHP and LiteSpeed
The obvious candidates are your websites and online shops. The ones that get missed are the PHP applications nobody thinks of as "the website": the staging copy of last year's site, an old campaign microsite, phpMyAdmin, a webmail or file-sharing install, the web front end of a monitoring tool, the admin panel of an appliance. They run the same runtime, and they are usually the last to be patched. If you run WordPress, PHP2Shell sits one layer below the plugin risk we covered in why WordPress sites keep getting compromised, and no plugin update fixes it.
The PHP branch matters too. The PHP project no longer maintains PHP 8.1 or anything older, so there is no official release for those branches. Fixes for them exist only as backports from your Linux distribution or an extended-support provider, or not at all if the server runs a PHP that nobody packages any more.
How Big This Is
The numbers explain why this one is being treated as an emergency.
- More than a million unpatched servers. Internet-wide scans counted between 1.5 and 2.6 million internet-facing PHP hosts on the day the patches shipped, and well over a million of them were still unpatched.
- Around a million with no upstream fix. Roughly a million of those hosts run PHP 5.x, 7.x, 8.0 or 8.1, branches the PHP project no longer releases fixes for.
- Attacks started before the patches. The first exploitation attempt hit a decoy server on 17 October, four days before disclosure.
- Then the volume exploded. One large network counted thousands of attempts in the ten hours before the announcement, tens of thousands within 45 minutes of it, hundreds of thousands within two hours, and millions since.
There is one honest caveat. At the time of writing, no large-scale compromise has been publicly confirmed, and most of the proof-of-concept code in circulation does not work. Some of it is fake and carries malware aimed at whoever runs it, so do not "test" your servers with an exploit you found on GitHub.
That caveat is not a reason to wait. It means the window is still open. It closes the day a reliable exploit starts circulating, and with this much attention on the bug, nobody should plan on that day being far away.
Not sure how many PHP servers you actually run? That is the right question to start with. Request a free PHP2Shell assessment and our security team will map it with you.
Step 1: Find Every PHP You Run, and Check the Right Version
Start with an inventory: servers, virtual machines, containers, and anything that ships PHP inside it. Then check versions carefully, because the obvious check gives the wrong answer.
On Ubuntu and Debian, php -v reports the upstream version, and distributions fix vulnerabilities by backporting patches without changing it. A fully patched Ubuntu 24.04 server still says PHP 8.3.6. The number that tells you whether you are safe is the package version:
dpkg -l 'php*' 'libapache2-mod-php*' | grep ^iiCompare what you see with the fixed Ubuntu packages:
- Ubuntu 26.10: php8.5
8.5.9-0ubuntu2.1or later - Ubuntu 26.04 LTS: php8.5
8.5.4-0ubuntu1.5or later - Ubuntu 24.04 LTS: php8.3
8.3.6-0ubuntu0.24.04.13or later - Ubuntu 22.04 LTS: php8.1
8.1.2-1ubuntu2.28or later - Ubuntu 20.04 LTS: php7.4
7.4.3-4ubuntu2.29+esm5or later, through extended security maintenance only - Ubuntu 18.04 LTS: php7.2
7.2.24-0ubuntu0.18.04.17+esm14or later, through extended security maintenance only
On RHEL, AlmaLinux, Rocky Linux and Fedora, list the installed packages and check them against your distribution's advisory for the two CVEs:
rpm -qa 'php*'If PHP comes from upstream builds, a third-party repository or an official container image, the upstream version is what counts: you need 8.5.12, 8.4.27, 8.3.36 or 8.2.35, or later. Anything on 8.1 or older from those sources has no fixed release.
For containers, check inside the running container, not the Dockerfile:
docker exec <container> php -vStep 2: Patch
On Ubuntu and Debian:
sudo apt update
sudo apt upgradeOn RHEL-family systems:
sudo dnf upgrade 'php*'For containers, rebuild on a fixed base image and redeploy. Pin the patch release and pull fresh layers, so the build cannot quietly reuse an old cached base:
FROM php:8.3.36-fpmdocker build --pull --no-cache -t my-app:php-8.3.36 .Then roll the new image out. A running container never changes because its image was updated. On Kubernetes, that means a new rollout, not just a new tag in the registry.
If you rely on unattended-upgrades, know what it does and what it does not do. It installs the fixed package, usually within a day. It does not restart your PHP workers, which brings us to the step that gets skipped.
Step 3: Restart PHP, the Step Everyone Skips
Installing a fixed package changes the files on disk. It does not change the code already loaded in memory. PHP-FPM workers and Apache children started before the upgrade keep running the vulnerable code until they are restarted, sometimes for weeks.
# PHP-FPM (adjust to your version)
sudo systemctl restart php8.3-fpm
# Apache with mod_php
sudo systemctl restart apache2Then confirm the service really started after the upgrade:
systemctl status php8.3-fpm | grep ActiveIf the "active since" time is older than the package upgrade, the server is still vulnerable, whatever the package list says. When in doubt, reboot.
Step 4: If You Cannot Patch Today
Some servers cannot be patched this week: a legacy application pinned to an old PHP, a vendor appliance with no update yet, a change freeze. For those, the PHP project lists partial mitigations. None of them makes an installation safe, and updating is the only complete fix, but they narrow the paths attackers are using right now.
Set them in php.ini or in the PHP-FPM pool configuration, then restart the workers:
; Most attack traffic so far goes through session upload progress
session.upload_progress.enabled = 0
; Keep requests away from the out-of-memory path
memory_limit = -1
; Use 32M instead if the application needs larger uploads
post_max_size = 8M
; PHP 8.5 only
fatal_error_backtraces = 0Three details matter:
- Do not apply them with
ini_set()or a.user.inifile. They have to be in place before PHP parses the request, and those come too late. - Unlimited memory trades one risk for another. A single heavy request can now exhaust the server, which is why
post_max_sizehas to come down with it. Watch memory while this is in place. - Keep session upload progress off for now, even after you patch. A related issue disclosed on 23 October (CVE-2026-115560) is mitigated the same way, until PHP's next regular release fixes it.
Then shrink the exposure around the server:
- Take it off the public internet if it does not need to be there. Admin panels, staging sites and internal tools belong behind a VPN or an IP allowlist.
- Enable your WAF or CDN's managed rules for PHP2Shell where your provider offers them. They block known attack patterns, not the vulnerability.
- Switch off what nobody uses. A forgotten microsite is cheaper to delete than to defend.
- Plan the upgrade. If a server runs PHP 7.4 or older, PHP2Shell will not be the last vulnerability it never receives a fix for.
Step 5: Check Whether Anyone Got In
Exploitation attempts started before the patches existed. Patching closes the door; it does not tell you whether someone walked through it first. Every server that was exposed deserves a look.
Start with files. Web shells are usually small PHP files with unremarkable names, so look for anything new or modified in the web root since mid-October:
find /var/www -name '*.php' -newermt '2026-10-15' -lsThen look at what the PHP user has been doing:
- Processes running as the web server user that are not PHP workers: shells,
curl,wget, crypto miners. - Outbound connections from the web server to addresses you do not recognise.
- Persistence: new cron jobs, new SSH keys, new administrator accounts in your CMS.
- Worker crashes in the PHP-FPM or Apache logs between 17 October and the day you patched. Memory-corruption exploits are noisy when they fail, and a burst of segmentation faults is a sign someone was trying.
If you find any of these, treat the server as compromised: isolate it, preserve the evidence, rotate every credential it could read, and rebuild it from a known-good state rather than cleaning it in place.
The Real Problem Is the PHP You Forgot
For most organisations, patching the main website is the easy part, and it happened the day the advisory landed. The risk sits elsewhere: the server nobody owns any more, the container image that has not been rebuilt in a year, the patched package whose workers were never restarted.
That is why "we patched" and "we are safe" are different statements. The first describes an action. The second needs evidence.
Get a Free PHP2Shell Assessment
If you are not certain where PHP runs across your estate, or whether the servers you patched are actually running the fixed code, our security team will check it with you at no cost.
The free assessment covers:
- Discovery of the internet-facing PHP across your domains, including the services nobody remembers
- Patch-level and restart verification on the servers you choose, against the fixed releases for your distributions
- A prioritised plan for anything that cannot be patched right away, with the mitigations that fit each case
You get a written list of what is exposed and what to do about it, with no obligation attached.
Request your free PHP2Shell assessment, or read more about our cybersecurity practice, from penetration testing to incident response.