Events Join us at the AWS Summit in Dubai on 30th September
Read

How to Fix PHP2Shell (CVE-2026-109618 and CVE-2026-109619)

Patch PHP2Shell on Ubuntu, RHEL, Docker, Windows and cPanel, restart every worker, and handle end of life PHP with no official fix available.

Introduction

Three national agencies said the same thing on 21 October: patch PHP or take the system offline. That is unusual language for a PHP2Shell patch advisory. It tells you how little room this one leaves you.

TLDR

Update to PHP 8.2.35, 8.3.36, 8.4.27, or 8.5.12, then restart every PHP worker, because a running process keeps the old code until it restarts. PHP 8.1 and older get no official release, so those hosts need a vendor package, a migration, or isolation. Configuration tweaks and WAF rules buy time and do not close the hole. PHP says it plainly: there are no complete PHP2Shell mitigation steps, and updating is the only safe choice.

PHP2Shell Fixed versions at a glance

Four branches got a release on 21 October. Everything older is a different conversation.

PHP2Shell · Fixed versions

Four branches got a fix. Everything older did not.

Released 21 October 2026. Find your branch, then check the support column, because that decides whether this is a patch or a project.

BranchAffectedFixed inSupport status
PHP 8.5
below 8.5.12
8.5.12
Active support
PHP 8.4
below 8.4.27
8.4.27
Active support
PHP 8.3
below 8.3.36
8.3.36
Security fixes only
PHP 8.2
below 8.2.35
8.2.35
Security fixes only
PHP 8.1, 8.0, 7.4
all versions
source backports only
End of life
PHP 7.3 and older
all versions, back to 5.4
no fix
End of life

Two things the version column will not tell you. A release candidate such as 8.5.12RC1 predates the fix and is still vulnerable. And a distribution backport fixes the code while keeping the old version string, so on a packaged install the changelog is the answer and the banner is not.

Release candidates are not fixed builds. An 8.5.12RC1 tag predates the release and still carries the flaw.

PHP2Shell Patch by platform

Start with hosts running Apache and mod_php. PHP rates that setup as highest risk, because one unauthenticated request reaches the engine before any application code runs.

PHP2Shell · Patch matrix

Update, then restart. Per platform.

Patch Apache with mod_php first. One unauthenticated request reaches the engine there before any application code runs.

Ubuntu, Debian
Packaged install
Updateapt update && apt upgrade
Confirm by changelog, not the version banner.
Restartsystemctl restart php8.3-fpm
Substitute your branch. Restart Apache too if you use mod_php.
RHEL, Rocky, Alma
Check the module stream
Updatednf update php\*
Run dnf module list php first to see which stream is enabled.
Restartsystemctl restart php-fpm httpd
Both, if the host serves through Apache.
Docker, Kubernetes
New image required
Updatedocker compose build --pull
Or docker compose pull on generic tags. Edit pinned tags by hand.
Recreatedocker compose up -d
A restart keeps the old image. Recreate, then read the version again.
cPanel, Plesk
Panel ships its own PHP
Updatethe panel's PHP update
A distribution update does not touch panel builds.
Restartper branch, every pool
On end of life builds the version may not change. Read the build date.
Windows
Replace the build
Updateofficial Win32 build
Match x64 or x86, thread safe or not, to what you run.
Restartthe web server
Then hunt bundled php.exe inside vendor applications.
Managed platforms
Answer varies by service
Updateread the provider bulletin
Some apply it for you. Some cannot patch a running instance at all.
Restartnew instance, then migrate
Custom runtimes and your own container images stay yours to update.
One command to catch what you missed sudo grep -lE '(php|libphp).*\(deleted\)' /proc/[0-9]*/maps 2>/dev/null

This lists every process still mapped to a PHP binary that has already been replaced on disk. When the restart is complete, it prints nothing.

Then go find the PHP you forgot. Admin panels, monitoring tools, firewalls, phone systems, webmail, file sync, database admin tools, helpdesks, wikis and learning platforms all ship PHP, often on ports nobody scans and sub paths nobody remembers.

Ubuntu and Debian

Install the PHP security update from your distribution, then restart PHP-FPM or Apache.

Your version string may not move. Distribution maintainers often backport the fix and keep the existing number, so confirm the package changelog names both CVE IDs rather than reading the banner.

RHEL, Rocky, AlmaLinux and Amazon Linux

Update the PHP packages your repository ships, then restart the service.

On EL8 and EL9, check which module stream is enabled before you update, because a host can have a newer PHP installed and still serve an older stream.

Docker and containers

A running container keeps the image it started from, so a pull alone changes nothing.

For generic tags, run docker compose pull, and then docker compose up -d. For images you build yourself, run docker compose build –pull so the cached base layer is not reused. If your Dockerfile pins a tag such as FROM php:8.4.27-fpm, you have to edit that line by hand, because a pinned tag never moves.

Then recreate the containers and read the version again. Images that install PHP through apt or apk depend on distribution packages, so they need a rebuild once those packages land.

Windows

Official Win32 builds for 8.2 through 8.5 are published for x64 and x86, in thread-safe and non-thread-safe variants. Replace the build, then restart the web server.

Watch for standalone binaries. A bundled php.exe or php-cgi.exe inside a vendor application is easy to miss, and nobody patches it.

cPanel, Plesk and CloudLinux

On a panel server, the panel’s update is the fix. Control panels ship their own PHP builds, so distribution updates don’t touch them.

The panel change log covers supported branches and backports the fix to end-of-life ones, one of the few places those get a binary.

One trap: on at least one panel, the patched end-of-life builds carry the same version number as the vulnerable ones and differ only by build date. Read the build date, not the version.

On CloudLinux, a PHP2Shell security-only update may not list the alt-php packages. Run a regular update instead.

Managed platforms and appliances

Check your provider’s bulletin before you do anything, because the answer differs by service even inside one cloud. Some managed platforms apply the fix for you. Some cannot patch a running instance at all and expect you to launch a new one from an updated image and migrate. Custom runtimes and container images are always yours to update.

Then go looking for the PHP you forgot. Admin panels, monitoring tools, firewalls, phone systems, webmail, file sync, database admin tools, helpdesks, wikis,, and learning platforms all ship with PHP, and they often run for years without anyone updating them.

Restart every PHP worker

Updating the package writes new files to disk. It does not change the code inside a process that is already running.

Restart PHP-FPM pools, Apache, LiteSpeed and any queue or cron workers that load PHP. Recreate containers rather than restarting them.

One command tells you whether you missed anything. This lists any process still mapped to a PHP binary that has been replaced on disk, and it should print nothing when you are done:

sudo grep -lE '(php|libphp).*\(deleted\)' /proc/[0-9]*/maps 2>/dev/null

Proving the restart actually took across a fleet is a bigger job than running the command once.

If you are on end-of-life PHP

PHP 8.1, 8.0, and 7.4 will receive no further releases from the project. The security team published source-only backport branches for people who build from source, with no tarball, no binary, and no version bump.

Vendors provide binaries on their own schedules, and coverage is uneven. Extended-support vendors, some distributions, and the control panels ship patched builds for these branches. Others have published no fix at all, and at least one major cloud distribution lists its old PHP packages as no fix planned. One popular hosting platform says outright that no PHP2Shell patch exists for 8.0 or 8.1 on its service.

PHP 7.4 · 8.0 · 8.1

No official release. Three paths, pick one.

PHP published source only backport branches for these versions. No tarball, no binary, no version bump. So the decision moves to you.

Start here Does your vendor ship a patched build for your branch?
Yes → path 1
Take the vendor backport
FastestStill end of life
  • Extended support vendors, some distributions and the control panels shipped builds for these branches
  • The version number may not change, so confirm by changelog or build date
  • Buys you time. It does not put you back on a supported branch
  • Check coverage first: some vendors published no fix at all for their old PHP packages
No, or not yet → path 2
Migrate to 8.3 or later
SlowestThe durable answer
  • The only option that ends the cycle instead of extending it
  • Needs application testing, so it is a project with a date, not a patch window
  • Target a branch with real support life left, not the next one up
  • Say the date out loud. An undated migration is how a host reaches 7.4 in the first place
Not today → path 3
Take it off the public internet
ImmediateBuys a decision
  • This is what three national agencies recommended for hosts that cannot be patched
  • Isolate the internet facing application rather than shutting the service down, where you can
  • Remember the ways traffic skips your edge: direct access on the origin IP, and DNS only hostnames pointing at the same server
  • Pair it with a dated plan, or it quietly becomes permanent

Pick before you promise. These paths cost different things and only one of them removes the problem. Decide which one each host is on, write it down with an owner and a date, and you can answer the question an auditor will actually ask.

So you have three paths. Take a vendor backport if your vendor has one, which is fastest and leaves you on a dead branch. Migrate to 8.3 or later, which is the durable answer and the slowest. Or pull the host off the public internet while you decide, as three agencies recommended for exactly this case.

Check which of the three you are on before you promise anyone a date.

If you cannot patch today

Every item here reduces exposure on a specific path. None of them makes a server safe.

  • Turn session upload progress off in the FPM pool. It closes the demonstrated session route and not the other lifecycle routes.
  • Cap request body size, part count, and headers per part. A size limit has a known gap because a multipart request without a usable declared length can slip past the first check.
  • Block multipart form data on any virtual host that does not accept uploads.
  • Set the memory limit to unlimited in the pool. This removes the out-of-memory trigger and still leaves an allocation failure path open.
  • Apply the settings in php.ini or the FPM pool, not through ini_set or a .user.ini file, and restart the pool afterward or nothing changes.

WAF rules are the same deal. One major CDN pushed rules to every plan, including the free tier, and its own CTO called them a stopgap. One major cloud updated its managed PHP rule group to cover both CVEs, and its bulletin still says patching is the only complete fix. Rules match request shapes, and attackers were mutating payloads within hours.

There is also a bigger hole in the WAF story. The edge only sees what passes through it. Test whether your origin answers directly on its IP address, and check for DNS-only hostnames such as staging, admin, or api records that point at the same server. A 200, 301, or 302 from the origin IP means anyone can skip your edge entirely.

After the fix

Assume the secrets are gone. One of these flaws reads memory from the PHP worker, which can hold passwords, tokens, API keys, and certificates from other requests. If the host faced the internet before you patched, rotate database credentials, API keys, and session signing keys.

Then look for what a visitor may have left behind. Check web roots for files you did not put there, look for a PHP process that spawned a shell or a network tool, and review bursts of memory errors or repeated 500 and 502 responses from before the patch.

Keep in mind that a successful run looks nearly silent. The worker doesn’t crash, and the response looks normal, so a quiet log isn’t an all-clear.

When the patch window closes

A fleet patch ends with a list of hosts and a hope. The next question is which ones anyone actually checked.

  • Secure.com Red Teaming retests your exposed PHP surface from outside, within a scope your team signs and can stop mid-run.
  • One target runs $5,000, with a 30-day verification re-scan included, rather than billed as a second engagement.
  • CSPM Teammate maps the attack path on your public hosts once your scanner reports the finding and the NVD record lands, without waiting for a KEV listing.
  • Workflows pause for a named approver in Slack or Teams before a restart, an isolation, or a key rotation runs.
  • Each host ends with a record naming what was checked, what was skipped, and what nobody knows yet.

FAQs

How do I fix PHP2Shell?
Update to PHP 8.2.35, 8.3.36, 8.4.27, or 8.5.12, or install a vendor package whose changelog names both CVEs. Then restart every PHP worker, because a running process keeps the old code until it restarts.
Do I need to restart after updating PHP?
Yes. Restart PHP-FPM, Apache, and LiteSpeed, and recreate containers instead of restarting them. Updating the package alone leaves running workers vulnerable.
What if I am running PHP 7.4, 8.0, or 8.1?
These branches get no official release. PHP publishes source-only backports for them, and some distributions, control panels, and extended-support vendors ship patched packages. The durable fix is moving to a supported branch.
Can a WAF protect me from PHP2Shell?
A WAF reduces risk and is not a fix. Rules match request shapes that attackers change, and the edge only sees traffic that passes through it. Confirm nobody can reach your origin server directly.
Should I take my PHP site offline?
If you cannot patch, that is what the agencies advised. The guidance was to take the system offline or isolate internet-facing applications from public networks until you can apply a fix.
Do I need to rotate passwords after patching PHP2Shell?
If the server faced the internet before you patched, assume its in-memory secrets were exposed. Rotate database passwords, API keys, and session signing keys.