Back

php2shell: how we protected more than 6 million websites


php2shell: how we protected more than 6 million websites

PHP is the language behind a large share of websites, including every WordPress site. On 21 October, the PHP project, which develops the language, released fixes for two critical PHP vulnerabilities nicknamed “php2shell”. They carry the identifiers CVE-2026-109618 and CVE-2026-109619 (a CVE is the public reference assigned to each known security vulnerability).

Their severity is rated 9.2 out of 10 (CVSS score): an attacker can run their own commands in the context of the targeted site, without any credentials. Pre-announced a few days earlier without technical details, these vulnerabilities quickly attracted scanners sweeping the web for vulnerable servers.

Our web application firewall was already monitoring for these attacks before the fixes were even published. We then deployed the fixes very quickly across the entire platform, for all fifteen PHP versions we offer, including the eight that received no official fix.

If your site is hosted on our shared web hosting plans, rest assured: it’s protected, whatever its PHP version. You don’t need to do anything, as the fixes have been fully deployed across the platform.

This post is for our customers and for anyone curious about how an operations team handles a critical vulnerability across a fleet of 5,000 servers.

The key facts

VulnerabilitiesTwo PHP engine vulnerabilities, nicknamed “php2shell”: CVE-2026-109618 (a mishandled memory overrun) and CVE-2026-109619 (data from one request that stays readable by the next)
SeverityCritical (CVSS score of 9.2 on a scale of 10): an attacker can run their own commands in the context of the targeted site, remotely and without a password
Versions fixed by the PHP projectThe recent versions: 8.2.35, 8.3.36, 8.4.27, and 8.5.12. A minimal fix is available for 7.4, 8.0, and 8.1
Versions with no official fixPHP 5.3 to 7.3: these versions are no longer maintained by the PHP project, but are still widely used
Our responseAttack detection on our web application firewall from the pre-announcement onwards, updates to recent versions, a fix written by our teams for PHP 5.3 to 7.3 (backporting), then testing and double review before deployment
What you need to doNothing. If your site still uses PHP 5 or 7, take the opportunity to move to a maintained version
Good to know if you developIf a script exceeds its memory limit (memory_limit), it stops dead: shutdown functions and destructors no longer run (details below)

What happened

Both vulnerabilities stem from the same mechanism: the way PHP interrupts a request that exceeds its memory limit.

PHP handles each HTTP request in a process that runs requests one after another. When a script exceeds its memory limit, PHP jumps abruptly to the end of the request, then cleans up before moving on to the next one.

  • CVE-2026-109618: if a script exceeds its memory limit while PHP is still preparing the request, PHP starts cleaning up data that is only half ready. This leaves memory in an inconsistent state. An attacker can trigger this precise moment by submitting a form with a file whose size is calculated for that purpose.
  • CVE-2026-109619: the clean-up between two visits is incomplete. Leftovers from the previous visit can be read by the next one. The easiest way in is file upload progress tracking (session.upload_progress). This feature reads the visitor’s session data before the site has even started, in other words at the most fragile moment.

Combined, these two flaws can, under certain conditions, allow arbitrary code to run in the context of the targeted site, without any credentials.

Why this is a challenge for a shared hosting provider

A dedicated server usually hosts only a very small number of sites, so a vulnerability there has a limited impact. On shared hosting, by contrast, many sites are grouped on the same server. When a PHP version is hit by a vulnerability, a large number of sites are affected at once. And since our customers don’t control the PHP engine, it’s up to us to fix it, quickly and everywhere at the same time.

Our platform has around 5,000 servers in Europe and Canada, hosting more than 6 million websites. Our customers are free to choose their PHP version, from 5.3 to 8.5. This freedom keeps older sites running, but it comes at a cost: more than half of these versions no longer receive any fixes from the PHP project.

The official fix for maintained versions runs to nearly 3,000 lines and reworks how memory overruns are handled at the heart of the engine. It can’t be applied as is to PHP 5.6 or 7.2. For 7.4, 8.0, and 8.1, the PHP project released a minimal out-of-cycle mitigation. For earlier versions, nothing exists, so it’s up to us, OVHcloud, to produce it.

Our response, layer by layer

We stacked several layers of protection: the first stops attacks at the platform’s entry point, while the others fix PHP itself. Specialists call this “defence in depth”. Here are our five steps, from the first alert to deployment on every server.

1. Detect attack attempts before the fix is even applied

The official fixed versions weren’t released until 21 October at 4 pm. Until then, sites had to be protected another way, and without delay.

Our web servers sit behind a web application firewall, a filter that every visit passes through before reaching a site, and that can discard suspicious requests. We integrated it ourselves, using the open-source tools OpenResty and NAXSI. As soon as the PHP project pre-announced the fixes, we taught it to recognise the telltale signs of the attack. These include a specific form field (the one that activates file upload progress tracking), certain user agents (the identifier every browser or bot sends), and typical request content. A second rule blocks the bots that started scanning the web for vulnerable sites.

This rule first ran in observation mode. It flagged the relevant requests without blocking them. Why the caution? That same form field is also used perfectly legitimately, for example by sites that display a progress bar while a file uploads. Blocking it outright could have broken those sites. Observing first let us measure how many sites would be affected, while staying ready to block at any moment.

2. Update as soon as the official fixes are released

On 21 October at 4 pm, the PHP project published its security advisories and the official fixed versions: 8.2.35, 8.3.36, 8.4.27, and 8.5.12. For PHP 8.2 to 8.5, which the PHP project still maintains, the situation is simplest. The official fix, which thoroughly reworks how memory overruns are handled, is included in these new versions. We took them as they were and compiled them for our platform. They then went through the same tests and the same gradual rollout as the others (steps 4 and 5).

For 7.4, 8.0, and 8.1, which normally no longer receive fixes, the PHP project released a minimal mitigation the same day, outside its usual schedule. We integrated it into our packages within hours.

3. Backport the fix ourselves to PHP 5.3 to 7.3

For PHP 5.3 to 7.3, which have reached end of life, the PHP project no longer releases any fixes. So we backported the fix, adapting the version designed for recent releases to these older ones ourselves. This is the most delicate part. The PHP engine has changed a lot since those versions, and the official fix can’t be applied to them as is. We extracted what could be adapted, in two parts.

Upload progress tracking can no longer run code before the script starts. The official mitigation published by the PHP project simply disables this feature. We chose to keep it, because hosted applications use it, but to harden it:

  • the session is decoded in a mode where no class is resolved, and neither autoloaders nor magic methods run;
  • the data is rewritten byte for byte;
  • if decoding fails, the session is left intact rather than destroyed. This is a deliberate departure from the official fix, so that a visitor is never logged out.

A memory overrun no longer lets the process continue in a corrupted state. The worker process ends immediately, and our process manager starts a fresh one. The “Allowed memory size exhausted” message remains visible in your error logs and on the page in development mode. Many of you rely on it every day, and the official mitigation would have removed it.

On top of this come more discreet hardening measures: limits on the headers accepted in a multipart body, strict enforcement of post_max_size while reading, and a systematic reset of the internal state between two requests.

4. Review together, and test

A badly written security fix can break sites, or even open a new vulnerability. Before any release, each version was therefore compiled and run through the PHP project’s automated test suites for the relevant areas: sessions, serialisation (the way PHP stores data so it can read it back later), and the engine core. We added non-regression tests written for the occasion, which check that what worked before the fix still works after it.

Automated tests don’t cover everything. Each backport therefore went through a cross code review. These independent reviews uncovered two defects that had slipped past the test suites, both fixed before release:

  • some complex data stored in a visitor’s session (an SPL container, in technical terms) could be rewritten incorrectly;
  • in one particular error case, the hardened protection stayed active for the rest of the script, when it should only have applied while the session was being read.

Finally, we compared our work with that of the Debian and Ubuntu communities, which also maintain older PHP versions for their users. They made choices similar to ours, which supports our approach.

5. Roll out gradually

Rather than updating all our servers at once, we move in stages. The new PHP versions, delivered as packages (ready-to-use installation files), are first installed on our pre-production clusters, the groups of servers we use for testing before real go-live. They only reach production once validated.

On each updated server, a simple check confirms two things: the fix is present in the installed PHP program, and PHP responds as expected to a file upload and a memory overrun. Any problem is caught before it reaches all sites.

If your site is on our shared hosting, you don’t need to update or restart anything. The automatic rollout is now complete across the entire platform.

What this changes for your sites

For the vast majority of sites, nothing visible. Two behaviours do change, though, and they’re worth knowing if you develop in PHP.

When memory_limit is exceeded, the script stops dead. The error message is unchanged, but:

  • functions registered via register_shutdown_function are no longer executed;
  • object destructors are no longer called;
  • content in the output buffer is lost.

If your application relies on these mechanisms to log an error or clean up resources, now is the time to check. That’s the price of complete protection on this path.

The upload progress bar keeps working. In the rare cases where a session can’t be decoded, the progress simply isn’t recorded and the visitor’s session is kept.

If your site still runs on PHP 5 or 7, take this post as a signal. We’ll keep protecting these versions as best we can. But a maintained version receives its fixes within hours, whereas an end-of-life version requires painstaking work for every vulnerability. You can switch versions in a few clicks from your Control Panel.

The timeline

Four days separated the pre-announcement from packages ready for fifteen PHP versions, eight of them with no official support.

Mid-OctoberThe PHP project pre-announces a critical fix for 21 October, with no technical details. First detection signature prepared.
21 October, morningSignature deployed in observation mode, then in blocking mode, on all of the platform’s web application firewalls.
21 October, 4 pmAdvisories published, along with fixed versions 8.2 to 8.5 and mitigations for 7.4, 8.0, and 8.1. The mitigations are integrated into our packages the same day.
21 October, eveningBackport to PHP 7.2 and independent review, then ports to 5.6, 7.0, 7.1, and 7.3 in parallel.
22 OctoberPorts to 5.3, 5.4, and 5.5. Process termination on memory overrun added, from 5.3 to 7.3.
23 OctoberTeam review, packages released for the eight end-of-life versions. Gradual rollout started and completed.

Share on: