PHP2Shell: A Critical Security Flaw Puts Millions of Websites at Risk. Pressific Clients Are Protected.
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
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.
PHP2Shell at a glance
| Question | Answer |
|---|---|
| Vulnerabilities | CVE-2026-109618 (GHSA-w8hw-w9fx-j79w) and CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp) |
| Severity | 9.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 vector | AV: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 types | Use after free (CWE-416), improper handling of exceptional conditions (CWE-755), access of an uninitialised pointer (CWE-824) |
| Who can exploit it | A remote attacker, without logging in |
| What's affected | The PHP runtime itself, on any server that handles web requests: PHP-FPM, Apache mod_php (highest risk), php-cgi, FrankenPHP and LiteSpeed |
| Fixed versions | PHP 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 websites | Protected, 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)
- A crafted request arrives at any PHP page
- PHP starts unpacking it, before any website code runs
- The request drives PHP past its
memory_limit, and PHP aborts in the middle of an update - The request ends, but some internal state is left half-built or still pointing at freed memory
Request 2, handled by the same worker
- PHP reuses the corrupted state as if it were valid
- 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.
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
- 5.4
- 5.5
- 5.6
- 7.0
- 7.1
- 7.2
- 7.3
- 7.4
- 8.0
- 8.1
- 8.28.2.35
- 8.38.3.36
- 8.48.4.27
- 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
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:
| Platform | Fixed package or release |
|---|---|
| Ubuntu 24.04 LTS | php8.3 8.3.6-0ubuntu0.24.04.13 (USN-8948-1) |
| Ubuntu 22.04 LTS | php8.1 8.1.2-1ubuntu2.28 (USN-8948-1) |
| Ubuntu 20.04 and older | Fixed 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 10 | php 8.3.36-1.el10_2 (RHSA-2026:87070), php8.4 8.4.27-1.el10_2 (RHSA-2026:87071) |
| RHEL 9 and 8 | Fixed module streams for PHP 8.2, 8.3 and the base packages (RHSA-2026:87072, 87073, 87079, 87080, 87151) |
| AlmaLinux 9 | ALSA-2026:87079, 87072 and 87151 |
| Alpine Linux | php83 8.3.36-r0, php84 8.4.27-r0, php85 8.5.12-r0, php82 8.2.35-r0 |
| Amazon Linux 2023 | PHP 8.2 to 8.5 fixed on 22 October. PHP 8.1 and Amazon Linux 2: no fix planned |
| cPanel EasyApache 4 | Version 25.91 fixes ea-php74 to ea-php85 |
| CloudLinux | Fixed ea-php and alt-php builds in the stable channel |
| Official Docker images | Tags 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
- CVE numbers reserved
The flaws had been reported to the PHP project privately by security researchers in August and September.
- First exploitation attempt seen
Amazon's threat intelligence honeypots record an attempt four days before public disclosure.
- Details leak early
The CVE numbers circulate before the planned disclosure. The PHP project brings its security release forward by a day.
- Cloudflare's firewall protections go live
About 11 hours before the fixes, for free and paid plans.
- 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.
- 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.
- 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.
- Vendors ship their builds
Linux distributions, control panels and container images publish fixed packages through 21 to 23 October.
- Pressific runs an additional verification
Every server and container checked again: fixed builds, restarted processes.
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:
$ 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:
$ 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 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 = 0inphp.inior your PHP-FPM pool configuration, then restart PHP. Setting it from inside your application withini_set()or a.user.inifile isn't enough, because it has to apply before a request is processed. - Keep request sizes modest. A sensible
post_max_sizeand 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,pythonorperlwith 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
.phpfile 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
- 1Cloudflare's Web Application FirewallManaged rules that block known PHP2Shell request patterns before they reach the server. Buys time, isn't a fix.
- 2Patched PHP on every serverThe official releases or the distribution's backport, installed host by host, starting with a standby server as a canary.
- 3Every 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.
- 4A sweep for signs of compromiseProcess trees, scheduled tasks, PHP files in upload folders and recently changed code, on every server.
- 5An additional verificationVersions, changelogs and process start times checked again on every host and container.
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
- Ask your host two questions: have the PHP2Shell fixes been installed, and has PHP been restarted since?
- Check you're on a supported PHP version. PHP 8.1 and older get no official fix, and updating WordPress alone won't help.
- Check your firewall. A properly configured web application firewall is an important extra layer, but it doesn't replace patching.
- Look for signs of compromise, using the checklist above, going back to 17 October.
- 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
- PHP security announcements and releases (php.net)
- GHSA-w8hw-w9fx-j79w, CVE-2026-109618 and GHSA-6wmf-4rv5-p3rp, CVE-2026-109619 (PHP project on GitHub)
- Today's PHP security release (The PHP Foundation)
- Supported PHP versions (php.net)
- USN-8948-1: PHP vulnerabilities (Ubuntu)
- CVE-2026-109618 (Debian security tracker)
- Critical security issue affecting PHP (UK National Cyber Security Centre)
- Cloudflare deploys protections against php2shell (Cloudflare)
- PHP2Shell exploitation before public disclosure (Amazon Threat Intelligence)
- Two critical RCEs in PHP core (Cisco Talos)
- php2shell: frequently asked questions (Tenable)
- PHP: the three letters that shut down sites all over the internet (The Verge)
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.


