PHP2Shell: A Critical Security Flaw Puts Millions of Websites at Risk. Pressific Clients Are Protected.

PHP2Shell security advisory card: CVE-2026-109618 and CVE-2026-109619, CVSS v4.0 9.2 critical, fixed in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35

Imagine waking up to find your business website has been hacked. The homepage has been replaced, customer enquiries are being intercepted, and visitors are being sent to fraudulent sites. Now imagine finding out that your website's own code wasn't even the problem.

That's the risk behind PHP2Shell, a pair of critical flaws in PHP itself, the programming language that runs most of the web, including every WordPress site. An attacker doesn't need to log in, doesn't need a vulnerable plugin and doesn't need your site to be complicated. On an unpatched server, a single crafted request to any PHP page can be enough to start an attack.

Every website managed by Pressific is protected against PHP2Shell. Cloudflare's firewall was blocking known attack patterns from 21 October, we installed the fixed PHP on every server we manage on 22 October, swept every server for signs of compromise (we found none), and ran an additional verification of every server and container on 24 October. Our clients don't need to do anything.

  • 9.2CVSS v4.0 score, critical
  • 0logins needed to attack
  • 2CVEs, one shared root cause
  • 21 Octfixed PHP released
Opening frame of the PHP2Shell explainer video: a cartoon burglar sneaking up to a car at night Short 路 watch Play the PHP2Shell explainer video

PHP2Shell in under a minute

If you'd rather watch than read, our short video explains what PHP2Shell is and why so many websites were exposed at once. Then read on for the technical detail: how the flaws work, which versions are fixed, and exactly how to check your own server.

Watch on YouTube

PHP2Shell at a glance

QuestionAnswer
VulnerabilitiesCVE-2026-109618 (GHSA-w8hw-w9fx-j79w) and CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp)
Severity9.2, critical, for both (CVSS v4.0, from the PHP project). NVD's CVSS v3.1 scores are 9.8 and 8.1.
CVSS v4.0 vectorAV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N: over the network, no privileges, no user interaction, full impact on the server
Weakness typesUse after free (CWE-416), improper handling of exceptional conditions (CWE-755), access of an uninitialised pointer (CWE-824)
Who can exploit itA remote attacker, without logging in
What's affectedThe PHP runtime itself, on any server that handles web requests: PHP-FPM, Apache mod_php (highest risk), php-cgi, FrankenPHP and LiteSpeed
Fixed versionsPHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35, released 21 October 2026, plus backports from operating system vendors
Does a WordPress update fix it?No. Only a PHP update does, followed by a restart of PHP
Pressific managed websitesProtected, no action needed

How the attack works

To see why PHP2Shell is so serious, it helps to know two things about how PHP serves a website.

PHP reads every request before your website's code runs. When a request arrives, PHP itself unpacks the query string, the cookies and any submitted form data or file uploads, and builds the variables your code will use. All of that happens before WordPress, a plugin or a login check gets a look in. So any page that runs PHP will do this work for any visitor, logged in or not.

PHP workers live for many requests. On a typical server, PHP-FPM or Apache keeps a pool of worker processes running and hands each one request after request. PHP is designed to wipe a worker's memory clean between requests. PHP2Shell is about what happens when that clean-up goes wrong.

Inside one PHP worker process

Request 1, sent by the attacker (no login)

  1. A crafted request arrives at any PHP page
  2. PHP starts unpacking it, before any website code runs
  3. The request drives PHP past its memory_limit, and PHP aborts in the middle of an update
  4. The request ends, but some internal state is left half-built or still pointing at freed memory

Request 2, handled by the same worker

  1. PHP reuses the corrupted state as if it were valid
  2. Data left in memory can leak, and with control over that memory an attacker can aim for code execution

The damage crosses the boundary between requests, which is why a single attacker request can affect what happens next.

A simplified view of the failure both CVEs share: an out-of-memory abort part-way through PHP's own work leaves state behind that the worker trusts on its next request. Based on the PHP project's advisory and the fix's own regression tests, which include cases named oom_request_parsing_next_request and oom_shutdown_function_next_request.

When PHP runs out of memory, it doesn't fail gracefully. It raises a fatal error and jumps straight out of whatever it was doing, an internal mechanism called a bailout. Code that was half-way through building or updating a data structure never gets to finish. Both PHP2Shell vulnerabilities come from that moment.

CVE-2026-109618: half-built data treated as valid

An attacker pushes PHP into running out of memory while some internal data is only partly set up. When PHP cleans up afterwards, it treats that unfinished data as if it were complete and valid, which corrupts memory.

CVE-2026-109619: stale references that survive the request

Under the same kind of error, PHP can keep references to memory that's freed when the request ends. A later request handled by the same process can follow those stale references, which can expose data or corrupt memory. The PHP project lists memory disclosure as a confirmed impact.

Why no login is needed, and why every PHP site counts

The trigger lives in PHP's own request handling, not in WordPress or a plugin. A brochure site with one PHP contact form is reachable in exactly the same way as a busy online shop. That's why the PHP project says every installation that serves web requests is at risk, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. The highest risk is on Apache with mod_php: according to the PHP project's advisory, mod_php carries on with PHP's request clean-up after a failed start, where PHP-FPM ends the worker instead. That makes FPM harder to exploit, not safe. And none of this can be fixed by updating WordPress, a theme or a plugin.

What the fix actually changes

This wasn't a one-line patch, and the size of it tells you something about the problem. We read the fix as Ubuntu shipped it in its security update (the package changelog lists every file it touches), because it's the most complete public record of what changed:

  • 106C source files changed
  • 26files in the Zend engine, PHP's core
  • 27bundled extensions hardened
  • 268new tests, 220 of them out-of-memory cases

The core of the change is in two places. In the Zend engine, including its memory manager (zend_alloc.c), the fix makes the bailout path leave PHP in a consistent state. In PHP's request handling, it hardens the code that unpacks incoming requests: main/rfc1867.c, which parses form submissions and file uploads, main/php_variables.c, which builds the request variables, and main/SAPI.c, the layer between PHP and the web server.

Around that, the same treatment is applied to the places where an attacker can make PHP allocate memory on request: string and array functions, unserialize(), JSON, regular expressions, multibyte strings, XML, SOAP, image handling, compression, sessions and more. The new tests are named for exactly that: oom_rfc1867_files, oom_unserialize, oom_json, oom_preg and over two hundred others, each one forcing an out-of-memory error at a different point and checking PHP comes out of it cleanly.

Upstream, the PHP project describes the change as replacing the abort-on-out-of-memory jump with a controlled unwind, and properly resetting the global state that could otherwise outlive a request.

Two practical consequences follow. First, it shows why an unsupported PHP version is such a risk: 8.1 and older get no official release, and back-porting a change of this size yourself isn't realistic. Second, it's a reminder that "upgrade PHP" isn't busywork: much of what keeps a server safe lives in code like this that no website owner ever sees.

Which versions are affected and fixed

The PHP project released fixed versions for every branch it still supports. Anything older than PHP 8.2 gets no official release. For 7.4, 8.0 and 8.1 the PHP security team published minimal source-code patches that hosts can build themselves, and older branches get nothing from the PHP project at all.

Every PHP branch since 5.4, by fix status

  1. 5.4
  2. 5.5
  3. 5.6
  4. 7.0
  5. 7.1
  6. 7.2
  7. 7.3
  8. 7.4
  9. 8.0
  10. 8.1
  11. 8.28.2.35
  12. 8.38.3.36
  13. 8.48.4.27
  14. 8.58.5.12
  • No fix from the PHP project
  • Minimal source patch only, no release
  • Fixed, but support ends 31 Dec 2026
  • Fixed release available
Only four branches get an official fixed release. Sources differ on how far back the flaws go: the CVE records list 8.2 to 8.5, NVD dates CVE-2026-109619 back to PHP 5.4, and some operating system vendors have patched older versions in their own long-term support. Sources: php.net, NVD, 21 October 2026.

Most servers don't run PHP straight from php.net. They use packages from their operating system or control panel, and those vendors ship their own fixed builds, often with an older-looking version number. These are the fixed packages published so far:

PlatformFixed package or release
Ubuntu 24.04 LTSphp8.3 8.3.6-0ubuntu0.24.04.13 (USN-8948-1)
Ubuntu 22.04 LTSphp8.1 8.1.2-1ubuntu2.28 (USN-8948-1)
Ubuntu 20.04 and olderFixed through Ubuntu Pro / ESM only (USN-8948-2)
Debian 13 (trixie)php8.4 8.4.27-1~deb13u1 (DSA-6574-1)
Debian 12 (bookworm)php8.2 8.2.35-1~deb12u1 (DLA-4848-1)
RHEL 10php 8.3.36-1.el10_2 (RHSA-2026:87070), php8.4 8.4.27-1.el10_2 (RHSA-2026:87071)
RHEL 9 and 8Fixed module streams for PHP 8.2, 8.3 and the base packages (RHSA-2026:87072, 87073, 87079, 87080, 87151)
AlmaLinux 9ALSA-2026:87079, 87072 and 87151
Alpine Linuxphp83 8.3.36-r0, php84 8.4.27-r0, php85 8.5.12-r0, php82 8.2.35-r0
Amazon Linux 2023PHP 8.2 to 8.5 fixed on 22 October. PHP 8.1 and Amazon Linux 2: no fix planned
cPanel EasyApache 4Version 25.91 fixes ea-php74 to ea-php85
CloudLinuxFixed ea-php and alt-php builds in the stable channel
Official Docker imagesTags 8.5.12, 8.4.27, 8.3.36 and 8.2.35. There's no fixed 8.1 image

If you're still on PHP 8.2, plan the next step now: php.net lists its security support as ending on 31 December 2026, after which it won't get fixes like this one.

Timeline: a leak, attacks and a race to patch

October 2026, times in UTC

  1. CVE numbers reserved

    The flaws had been reported to the PHP project privately by security researchers in August and September.

  2. First exploitation attempt seen

    Amazon's threat intelligence honeypots record an attempt four days before public disclosure.

  3. Details leak early

    The CVE numbers circulate before the planned disclosure. The PHP project brings its security release forward by a day.

  4. Cloudflare's firewall protections go live

    About 11 hours before the fixes, for free and paid plans.

  5. Fixed PHP released, advisories published

    PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. The UK's NCSC issues an advisory the same day.

  6. Broad scanning and exploitation attempts

    Amazon reports attempts from the early hours of 21 October and broad exploitation attempts since. Cisco Talos sees attempts within hours of disclosure, mostly automated scanning.

  7. Pressific has patched and tested every server

    Fixed PHP installed, every PHP process restarted, every website tested. Every server was then checked for signs of compromise the same day.

  8. Vendors ship their builds

    Linux distributions, control panels and container images publish fixed packages through 21 to 23 October.

  9. Pressific runs an additional verification

    Every server and container checked again: fixed builds, restarted processes.

Sources: PHP Foundation, php.net, Amazon Threat Intelligence, Cloudflare, Cisco Talos, NCSC, and our own patch log.

One more thing to watch. On 23 October the PHP project disclosed a separate, not yet fixed issue, CVE-2026-115560, which only affects servers with an unusual session configuration. Its advice for now is to turn off session.upload_progress, which very few websites use.

How to check your own server

There are three questions to answer, in this order: which PHP build is installed, whether that build contains the fix, and whether the PHP processes actually serving your website have been restarted onto it.

1. In WordPress

Go to Tools > Site Health > Info and open the Server section. The PHP version is listed there. On most hosts this tells you the branch (8.3, 8.4) but not whether a backported fix is in place, so treat it as a starting point and confirm with your host.

2. On the server

Here's what it looks like on two of our own servers, copied from the terminal on 25 October. The first runs the PHP packages maintained by Ond艡ej Sur媒, which track php.net releases, so the version number itself is the proof:

Ubuntu 24.04 路 Sur媒 PHP packages
$ php -v | head -1
PHP 8.3.36 (cli) (built: Oct 21 2026 14:32:55) (NTS)
$ dpkg-query -W -f='${Package} ${Version}\n' php8.3-fpm
php8.3-fpm 8.3.36-1+ubuntu24.04.1+deb.sury.org+1

The second uses Ubuntu's own packages. Here the version string still says 8.3.6, because Ubuntu backports the fix into its existing build. The proof is the package revision and the CVE entries in the package changelog:

Ubuntu 24.04 路 Ubuntu's own PHP packages
$ php -v | head -1
PHP 8.3.6 (cli) (built: Oct 19 2026 15:16:58) (NTS)   # looks old, isn't
$ dpkg-query -W -f='${Package} ${Version}\n' php8.3-fpm
php8.3-fpm 8.3.6-0ubuntu0.24.04.13
$ zgrep -c CVE-2026-109618 /usr/share/doc/php8.3-common/changelog.Debian.gz
2
$ systemctl show php8.3-fpm -p ActiveEnterTimestamp
ActiveEnterTimestamp=Sat 2026-10-24 06:47:41 UTC   # restarted after the upgrade

On Red Hat style systems the equivalent check is rpm -q --changelog php-common | grep -i CVE-2026-10961. If the changelog doesn't mention either CVE, the fix isn't in that build.

3. Restart PHP, then check again

This is the step most often missed. Installing the new package replaces the files on disk, but PHP-FPM pools and Apache workers that were already running keep the old code in memory until they're restarted. Until they're restarted, those processes are still running the vulnerable code. Compare the service's start time with the time of the upgrade, as in the last command above, and restart php8.3-fpm (or Apache, for mod_php) if it started before the upgrade.

4. Containers and control panels

A Docker container built from a php: image keeps the PHP it was built with. Restarting it changes nothing: rebuild it with the base image pulled fresh (docker compose build --pull), redeploy, then confirm with docker exec <container> php -v. Here's one of ours after the rebuild:

Docker 路 php:8.3-apache base image
$ docker exec accounts_php php -v | head -1
PHP 8.3.36 (cli) (built: Oct 21 2026 15:57:18) (NTS)

On cPanel, Plesk and similar panels, PHP usually comes from the panel vendor's own builds (EasyApache, alt-php and so on), and each version you've enabled has to be updated, not just the default one. If you're on shared hosting you can't do any of this yourself, so ask your host directly whether the PHP2Shell fixes are installed and whether PHP has been restarted since.

If you can't patch today

Patching is the only complete fix, and the PHP project is explicit about that. If you genuinely can't update straight away, these steps reduce the risk while you arrange it:

  • Put a web application firewall in front of the site. Cloudflare's free and paid managed rules include PHP2Shell protections, and AWS WAF and Imunify360 have rules too. Check the rules are set to block, not just log. A firewall only protects traffic that goes through it, so it won't help if your server can be reached directly.
  • Turn off session upload progress. Set session.upload_progress.enabled = 0 in php.ini or your PHP-FPM pool configuration, then restart PHP. Setting it from inside your application with ini_set() or a .user.ini file isn't enough, because it has to apply before a request is processed.
  • Keep request sizes modest. A sensible post_max_size and upload limits at the web server reduce how much work an attacker can make PHP do on each request.
  • Restart PHP after any change, so every worker picks it up.

None of these is a substitute for the update. Treat them as a way to buy days, not weeks.

How to look for signs of compromise

Patching closes the door. It doesn't tell you whether anyone walked through it while it was open, and for PHP2Shell the door was open in public for about two days before fixes existed, and Amazon's honeypots recorded a first attempt four days before that.

Two things make this harder than usual. The flaws fire while PHP is still setting up the request, so a successful attack can look like an ordinary, perhaps slightly odd, request in your access logs. And an attacker who gets code execution runs as your PHP user, with the same permissions as your website. So look at what the PHP processes did, not just at what was requested.

Our own sweep covered the first four checks below on every server. The others are worth adding. Treat this as a starting point, not a guarantee: if you find something you can't explain, treat the server as compromised and bring in help. Look back to at least 17 October.

  • Processes started by PHP. PHP-FPM or Apache workers shouldn't normally start shells or download tools. Look for sh, bash, curl, wget, python or perl with a PHP worker as the parent (ps -eo user,pid,ppid,lstart,cmd --forest), and check your endpoint protection's alerts for the same pattern. This is where detection tools are focusing, because the requests themselves are hard to tell apart.
  • PHP files where they don't belong. Any .php file inside an uploads or cache folder is suspicious on a WordPress site: find /path/to/site/wp-content/uploads -name '*.php'.
  • Recently changed code. List PHP files modified since the exposure window opened, for example find /path/to/site -name '*.php' -newermt 2026-10-17, and account for every one. Plugin auto-updates will show up here, so compare against your update history.
  • Scheduled tasks and persistence. Review the crontab for every site user and for root, systemd timers, and any new SSH keys in authorized_keys.
  • New admin accounts. In WordPress, check Users for administrators you don't recognise.
  • Outbound connections. A web server talking to unfamiliar addresses (ss -tnp) is worth a closer look.
  • Odd memory errors and crashing workers. Out-of-memory errors that don't name a script (Allowed memory size of ... bytes exhausted ... in Unknown on line 0) and bursts of PHP workers exiting on signals are both worth a closer look, especially between 17 and 22 October.

On our servers this sweep found nothing: no unexpected processes, no PHP in upload folders, no unexplained code changes, and scanner requests that had been rejected.

How Pressific clients were protected

We don't rely on a single safeguard. PHP2Shell was met by several layers, each one covering a different way things can go wrong.

Defence in depth, outside in

  1. 1
    Cloudflare's Web Application FirewallManaged rules that block known PHP2Shell request patterns before they reach the server. Buys time, isn't a fix.
  2. 2
    Patched PHP on every serverThe official releases or the distribution's backport, installed host by host, starting with a standby server as a canary.
  3. 3
    Every PHP process restarted and every site re-testedNo worker left running the old code. Each website rendered through its own PHP pool before and after, with identical results.
  4. 4
    A sweep for signs of compromiseProcess trees, scheduled tasks, PHP files in upload folders and recently changed code, on every server.
  5. 5
    An additional verificationVersions, changelogs and process start times checked again on every host and container.
Each layer covers a different failure. A firewall can be bypassed by a new variant, a patch can be installed without a restart, and a restart doesn't tell you whether anyone got in during the two days the flaws were public.

Layer one: the firewall. The large majority of the websites we manage sit behind Cloudflare. Cloudflare rolled out PHP2Shell protections at 03:02 UTC on 21 October, about 11 hours before the fixed releases came out, so our clients were shielded at the edge before the fixes even existed.

Layer two: patched PHP. By 06:06 UK time on 22 October we had installed the fixed PHP on every server we manage and tested the websites on them. We updated a standby server first, rendered every website on it through its PHP pool, compared the results with the run before the update, and only then moved on to the production servers. We installed only the PHP packages, by name, rather than every pending system update, so nothing unrelated changed on a live server during an emergency. The PHP service restart on our main hosting server took under half a second, across 90 PHP pools.

Layer three: containers too. Some of our own applications run PHP inside Docker containers. Those don't pick up a server's PHP update at all, so we rebuilt each one from a freshly pulled, patched base image and kept the previous images for an instant rollback. That included one older application that was still on PHP 8.1, which will never get an official fix: we moved it to PHP 8.3 the same day.

Then we checked for intruders. The flaws were public for about two days before anyone could patch, so we inspected every server for the signs described above. We found no compromise: the only suspicious traffic was automated scanners whose requests were rejected.

And then we checked again. On 24 October we ran an additional verification on every server and container, confirming the fixed builds and that every PHP process had been restarted since the upgrade. Client sites on partner hosting platforms were covered by those providers' own platform-wide patching, which we confirmed against their published notices.

The result: Pressific-managed websites are protected against these vulnerabilities, and our managed hosting clients don't need to do anything.

We don't just give you backup tools. We take responsibility.

Every website owner should ask one simple question: if my website were compromised tomorrow, who would actually put it right?

Many hosting services hand you backup software and leave the restoring to you. That's not how Pressific works. Our managed hosting includes guaranteed backups and hands-on recovery. If something goes wrong, we take responsibility for restoring your website, and if we can't restore it from backup, we'll rebuild it for free.

What to do if Pressific doesn't manage your website

  1. Ask your host two questions: have the PHP2Shell fixes been installed, and has PHP been restarted since?
  2. Check you're on a supported PHP version. PHP 8.1 and older get no official fix, and updating WordPress alone won't help.
  3. Check your firewall. A properly configured web application firewall is an important extra layer, but it doesn't replace patching.
  4. Look for signs of compromise, using the checklist above, going back to 17 October.
  5. Make sure your backups actually work, and find out who's responsible for restoring them.

Questions people are asking

My server says PHP 8.3.6. Am I vulnerable?

Not necessarily. Ubuntu 24.04's own PHP packages still report 8.3.6 after the fix. Check the package version instead: 8.3.6-0ubuntu0.24.04.13 or later is fixed. The commands are in the section on checking your server.

I'm behind Cloudflare. Do I still need to patch?

Yes. Cloudflare's rules block known attack patterns, and Cloudflare itself says to patch. New variants can slip past signatures, and anyone who can reach your server directly bypasses the firewall completely.

Is PHP-FPM safe, since mod_php is the highest risk?

No. The PHP project rates every web-facing setup as at risk. PHP-FPM is harder to exploit, not immune.

We're on PHP 7.4 or 8.1. What now?

There's no official fixed release. If your operating system vendor offers extended support (Ubuntu Pro, RHEL, CloudLinux and others have shipped fixes for older versions), install it. Otherwise, upgrading to PHP 8.3 or newer is the real fix, and the mitigations above are a stopgap at best.

I updated PHP. Why does my host say to restart it?

Because PHP workers that were already running keep the old, vulnerable code in memory. Until PHP-FPM or Apache is restarted, the update isn't fully in effect.

Security isn't something you should have to think about every morning

PHP2Shell is a reminder that website security goes far beyond passwords and plugin updates. It covers the servers, programming languages, network infrastructure, monitoring, backups and recovery procedures that keep a business online. If you'd like to see how your own setup measures up, our WordPress security checklist is a good place to start.

We don't just host websites. We look after them. Discover Pressific managed hosting.

Sources and further reading

First published 22 October 2026, updated 25 October 2026 with technical detail, vendor packages and verification steps. This advisory describes PHP2Shell and Pressific's protections as of the update date.

Stop worrying about your website.
Let Pressific handle it properly.

View Plans

Starting at less than a 鈽曪笍 per day!