On October 21, 2026, the PHP project shipped an emergency release, and the NSA put out an advisory the same day telling organizations to patch. The two flaws behind it, nicknamed PHP2Shell, let an attacker take over a web server running PHP remotely, with no login. They sit in PHP itself, so a well-written app on an old PHP is still exposed.
This post covers what PHP2Shell is, which versions are affected, how to check what you run in a few minutes, how to patch, and what to do if you cannot update today.
What is PHP2Shell?
PHP2Shell is the nickname for two critical flaws in PHP, CVE-2026-109618 and CVE-2026-109619. Both allow unauthenticated remote code execution: an attacker who can send requests to your server can run their own code on it, without an account or any access first. PHP fixed both in releases published on October 21, 2026.
The PHP security advisory describes them in plain terms. The first comes from how PHP handles running out of memory: the failure can interrupt a request while internal data is half set up, and the cleanup then treats that bad data as valid. The second leaves internal state from one request behind after its memory is freed, so the next request on the same worker can use it. The full details are in GitHub advisories GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp.
The NSA's advisory stresses the part that matters most for small teams. These are flaws in PHP, not in your application or its configuration. Servers running an affected PHP version are exploitable, and the NSA expects attackers to start using them.
Which PHP versions are affected by PHP2Shell?
Every release before 8.5.12, 8.4.27, 8.3.36 or 8.2.35 on its own branch is affected. Those four releases are the fixed versions for the four supported branches. PHP 8.1 and older are also affected and get no official release, because the PHP project no longer supports them.
| Your branch | Fixed in | What to do |
|---|---|---|
| PHP 8.5 | 8.5.12 | Update to 8.5.12 or newer |
| PHP 8.4 | 8.4.27 | Update to 8.4.27 or newer |
| PHP 8.3 | 8.3.36 | Update to 8.3.36 or newer |
| PHP 8.2 | 8.2.35 | Update to 8.2.35 or newer |
| PHP 8.1 and older | No official release | Move to a supported branch, or use a vendor backport |
The patch number matters. PHP 8.3.30 is on a supported branch and is still exposed. Only 8.3.36 and later carry the fix.
Is my server exposed to PHP2Shell?
Your server is exposed if it runs an affected PHP version that answers web requests. PHP's advisory names PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. It rates Apache with mod_php as the highest risk, because a demonstrated exploit fires before any of your application code runs.
A few setups are not affected at all. A static site, or an app written in Node, Python, Go or another language, does not run PHP. A PHP script that only runs from the command line, such as a build step that runs Composer, does not serve requests, which is the attack path the advisory describes. Managed hosting is different again: if your host runs PHP for you, it is their job to patch it, but it is still worth checking their status page or support notes to confirm they have.
The setups to worry about are the ones you run yourself: a VPS with PHP installed, a Docker image built on the official php image, a WordPress or Laravel server you set up, or an old project that is still online because nobody turned it off.
How do I check which PHP version I am running?
Run php -v on the server to see the command-line version, then confirm the version your web server actually uses, because they can differ. In Docker, read the FROM php: line in your Dockerfile. Compare the full version, including the last number, with the fixed releases above. On Debian or Ubuntu packages the upstream number may not change, because fixes are backported, so check your distribution's security notice for the fixed package version.
Here are the places to look, from quickest to most thorough:
- On a server you can log into: run
php -v. If you use PHP-FPM, also runphp-fpm -vor check the service name, since a server can have more than one PHP installed. - In Docker: open the Dockerfile and read the last
FROMline.FROM php:8.3.30-apacheis exposed. A tag with no patch number, such asphp:8.3-fpm, means the version depends on when the image was last built. - In a Composer project: look for
config.platform.phpincomposer.json. It shows the PHP version your dependencies target, not the version your server runs, so treat it as a clue and confirm on the server. - Through the web server: a temporary page that calls
phpinfo()shows the exact version the web server runs. Delete it right after, because it shows details an attacker would love.
How do I patch PHP2Shell?
Update PHP to 8.5.12, 8.4.27, 8.3.36 or 8.2.35 or newer, then restart PHP-FPM or your web server so every worker loads the new version. On Linux, use your distribution's packages. In Docker, rebuild on a fixed tag and redeploy. Verify the running version afterwards.
PHP says Linux distributions and long-term support vendors received the patches in advance, so check your vendor for updated packages. Then run your normal package update, for example sudo apt update && sudo apt upgrade on Debian or Ubuntu, then restart the PHP service. Source builds are on the PHP downloads page, and Windows builds are on its Windows page.
For Docker, change the base image to a fixed tag such as php:8.3.36-fpm and rebuild with docker build --pull so you do not reuse a cached old layer. Pin the full version rather than php:8.3-fpm, so a stale image cannot quietly come back on the next deploy, and bump it when the next PHP security release ships. Then check the version inside the running container, not just the Dockerfile.
What if I cannot update PHP today?
Patching is the only complete fix. If you truly cannot update today, PHP lists settings that block the known attack paths but do not make a server safe, and the NSA recommends taking a system offline until it can be fully patched. Treat the settings below as a short bridge, not a fix.
From the PHP advisory, in summary:
- For the memory flaw: set
memory_limit=-1in a way your app cannot override, set a lowpost_max_size(8M if you do not need uploads, 32M if you do), and enforce request size limits at your web server or proxy. Do not useRLIMIT_ASorRLIMIT_DATAas a memory cap, because they can trigger the flaw. - For the stale state flaw: set
session.upload_progress.enabled=0inphp.inior your FPM pool, not withini_set()or an FPM.user.ini, and restart every worker. On PHP 8.5, also setfatal_error_backtraces=0.
Read the advisory itself before relying on any of these, because it explains the limits of each one in detail. Then put the real update on your calendar for this week.
What about PHP 8.1, 8.0 and 7.4?
PHP 8.1 and older get no official PHP2Shell release, because they are past end of life. The PHP team published emergency source patches for 7.4, 8.0 and 8.1 for people who build PHP themselves, and some vendors ship backported packages. The lasting fix is moving to a supported branch.
The source patches live in branches on GitHub, for example the PHP 8.1 branch. They exist to buy time. The NSA's advisory also tells organizations to replace end-of-life PHP services that cannot be patched, and that is the right plan for anything still on 7.4 or 8.0.
Catching it before you deploy
A server patched today can become exposed again tomorrow if an old Dockerfile or a cached image is redeployed. The free IOnclad browser scanner now flags Dockerfiles whose base image pins a PHP version exposed to PHP2Shell, including end-of-life versions. It runs entirely in your browser, with no signup, and your code stays in the tab.
It is one check among many. Our pre-launch security checklist covers the rest of what tends to go wrong before a launch, and insecure infrastructure defaults explains why config files deserve the same review as code. For the wider picture of web risks, see the OWASP Top 10 for solo developers.
This post is part of our app security guides for indie developers.