Skip to main content
Illustration of a server patch log upgrading PHP 8.2, 8.3, 8.4 and 8.5 to their October 2026 security releases
Cybersecurity

PHP2Shell: How We Patched Every Client Server Overnight

Xelent Solutions October 22, 2026 10 min read

On 21 October 2026 the PHP project shipped an urgent security release: PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. The releases fix two critical vulnerabilities, CVE-2026-109618 and CVE-2026-109619. Both are rated 9.2 under CVSS v4.0, and both can allow unauthenticated remote code execution.

Security researchers at Wiz, who found and reported the bugs, have named them PHP2Shell. The PHP release notes are blunt about what to do: there are no complete mitigations, and updating is the only safe choice.

This post covers three things. First, what actually broke, in plain language. Second, how our team rolled the fix out across the servers we manage for clients overnight, so their sites kept running without anyone having to ask us. Third, what Laravel, PHP and Forge users should do now, and how to stay ahead of the next release like this one.

What the two vulnerabilities are

Most security issues you hear about in the PHP world live in application code: a vulnerable WordPress plugin, an unvalidated upload, a SQL injection in a custom form. These two are different. They live in the PHP engine itself, so a perfectly written application is still exposed if the PHP binary underneath it is vulnerable.

CVE-2026-109618, RCE via out-of-memory corruption. When a PHP request runs out of memory, PHP aborts it abruptly. Some code paths did not handle that abort cleanly, which could leave internal request data only partly set up. The cleanup that runs afterwards could then treat that half-built data as valid. An attacker who can reliably push a request into an out-of-memory condition can turn that into code execution.

CVE-2026-109619, RCE via stale global state. PHP keeps some internal state that briefly points into memory owned by the current request. In certain cases that state was not reset properly, so it could still point to memory that had already been freed. The next request handled by the same worker could read that stale state before it was initialised. Again, an attacker can steer this into remote code execution.

A few details make this release stand out:

  • No login is needed. The official advisory describes a demonstrated exploit in which an unauthenticated request triggers the attack before any application code runs. Risk is highest on servers using mod_php with Apache, but PHP-FPM setups are affected too.
  • The bugs are old. According to the Forge advisory, both issues affect PHP versions dating back to 2004. Every PHP version you are likely to find on a production server is vulnerable until it is patched.
  • PHP 8.1 and older will not be fixed by the PHP project. Those versions are end of life. Some Linux distributions and long-term support vendors offer backported patches, but if you rely on the official releases, the fix is to move to a supported version.
  • PHP 8.2 is close to the end of its own support. The 8.2.35 release notes confirm that PHP 8.2 reaches end of life on 31 December 2026. If you are patching 8.2 today, plan the upgrade too.

According to the timeline Wiz published, the first bug was found on 19 August 2026, reported to the PHP security team on 24 August, and fixed in a coordinated release on 21 October. PHP gave advance notice of the release a day earlier, and Linux distributions received the patches ahead of time.

How we handled it: overnight, before clients had to ask

When a release like this lands, our clients should not have to email us asking whether they are safe. Patching is part of the maintenance we already run for the Laravel and PHP applications we build and host. Here is what that looked like in practice.

1. We acted on the advance notice

PHP announced on 20 October that a security release was coming with two critical fixes. That one day mattered. Before any patch existed, we used it to refresh our inventory: every server we manage, every PHP version installed on each one (not only the version the site uses), and which servers run queue workers, Horizon, Octane or Reverb.

2. We checked where PHP actually comes from

This is the step many teams miss. On Laravel Forge, PHP is installed from Ondřej Surý's PHP packages, not from Ubuntu's own repositories. Forge's own advisory states that its automatic security updates do not patch PHP, because Ubuntu's unattended upgrades only cover Ubuntu's security repository.

So "we have automatic updates switched on" was not an answer. Every server needed an explicit PHP upgrade.

3. We confirmed the patched packages were really available

Patched packages usually reach the package repositories shortly after the upstream release, but not always instantly. Before touching a server we confirmed that the candidate package version matched the fixed release (for example 8.4.27 for PHP 8.4). Installing an older build and believing you are patched is worse than knowing you are not.

4. We patched staging first, then production in a low-traffic window

Upgrading PHP restarts PHP-FPM, which can mean a few seconds of interruption. We applied the update to staging environments first and ran smoke tests on the key journeys: login, checkout, forms, API endpoints and scheduled jobs.

We then patched production during each client's quietest hours. Because our team works in a different time zone from most of our UK, US and Middle East clients, their overnight is our working day. That let us patch while their traffic was at its lowest, with engineers fully awake and watching.

5. We restarted everything that keeps old PHP in memory

Upgrading the package restarts PHP-FPM, but long-running CLI processes keep running the old, vulnerable PHP until they are restarted. On every Laravel application we restarted:

  • queue workers (php artisan queue:restart)
  • Laravel Horizon (php artisan horizon:terminate, with Supervisor bringing it back)
  • Laravel Octane (php artisan octane:reload)
  • Laravel Reverb and any other daemons configured on the server

6. We verified, and wrote it down

For each server we confirmed that both the CLI and PHP-FPM reported the fixed version, checked error logs and uptime monitors, and recorded the before and after versions. Clients woke up to a short note saying what was patched and when, rather than to a news story and a worried question.

How to patch your own Laravel and Forge servers

If you manage your own servers, here is the short version of what Laravel Forge recommends, plus a few lessons from our own rollout.

Know your target versions

PHP branchPatched version
8.58.5.12
8.48.4.27
8.38.3.36
8.28.2.35
8.1 and olderNo official fix. Upgrade to a supported version

Check what you are running

SSH into the server and list every installed PHP version, then check each one:

ls /etc/php
php8.4 -v

Open your server, go to the PHP tab, and choose Update PHP X.X for each installed version. Do this for every version on the server, including versions no site currently uses. Forge also repairs the PHP package source if it has drifted, which is why it recommends the dashboard over doing it by hand.

If you look after many servers, you can trigger the update through the Forge API, or create a Forge Recipe that runs the manual commands as root across all of them.

Or update manually over SSH

Refresh the package lists and confirm the candidate version matches the table above:

sudo apt-get update
apt-cache policy php8.4-fpm

Then upgrade only the packages already installed for that version, keeping your existing php.ini and FPM pool configuration:

sudo apt-get install --only-upgrade -y \
  -o Dpkg::Options::="--force-confold" \
  $(dpkg -l 'php8.4*' | awk '/^ii/ {print $2}')

Repeat for each PHP version on the server.

Restart long-running processes and verify

Restart queue workers, Horizon, Octane, Reverb and any other background processes, then confirm both the CLI and FPM are on the patched build:

php8.4 -v
php-fpm8.4 -v

Not on Forge?

  • Docker: rebuild and redeploy your images from an updated base image. A running container does not update itself, and an old image tag pinned in a deploy pipeline will happily ship the vulnerable version again.
  • Other server panels and plain Ubuntu: check where your PHP packages come from. If it is a third-party repository, your OS's automatic updates may not cover it, just as with Forge.
  • Shared hosting: ask your host which PHP build they are running and when they will patch. If you cannot get a clear answer, that is useful information in itself.
  • Local development: update your local PHP too (for example through Laravel Herd), so your development environment matches production.

If you truly cannot update today

The PHP security advisory lists temporary php.ini and FPM pool changes that reduce exposure, and services such as Cloudflare and Fastly have published WAF protections. Treat these as a bridge for hours, not a fix. The advisory itself states they do not make an installation safe.

Wiz also suggests watching for signs of attempted exploitation: unusual multipart requests followed by memory-limit errors, bursts of HTTP 500 responses, oversized or malformed PHPSESSID cookies, and PHP workers restarting unexpectedly.

What this means for the PHP community

It would be easy to read a release like this as bad news for PHP. We see it differently.

Coordinated disclosure worked. Researchers found the bugs, reported them privately, and gave the PHP security team two months to fix them properly. Distributions got the patches in advance, PHP gave a day's public warning, and Forge published step-by-step guidance on release day. That is how a mature ecosystem should behave.

Secure application code is not enough. Laravel gives you excellent protection against the common web vulnerabilities, but it cannot protect you from a flaw in the runtime underneath it. Security is a stack: application, framework, packages, runtime, operating system and server configuration. Each layer needs an owner.

Version debt is security debt. Thousands of sites still run PHP 8.1, 8.0 or even 7.x because "it still works." As of this week, those sites have a critical, publicly documented remote code execution vulnerability with no official fix. Keeping PHP versions current is not housekeeping. It is what decides whether a fix exists for you when the next advisory lands.

"Managed" needs reading carefully. Many teams assumed their platform's automatic updates covered PHP. On Forge, by design, they do not. Know exactly what your hosting platform patches for you and what it leaves to you.

Where to watch for the next one

Security news reaches different people through different channels. These are the sources we follow, and the ones we recommend to any team running PHP in production:

  • php.net news archive and its RSS feed: the official source for releases, advance notices and end-of-life dates.
  • php-src security advisories on GitHub: the detailed technical advisories behind each CVE. Watching the repository's security alerts is a simple way to get notified.
  • The oss-security mailing list: where open-source vulnerabilities are discussed in detail, often with distribution-specific notes.
  • CVE.org and the NVD: authoritative records for affected and fixed versions, and severity scores.
  • Laravel Forge documentation and the Laravel blog: practical, platform-specific patching steps for Forge users.
  • Your package source: for Ubuntu servers using Ondřej Surý's PHP packages, that repository is where patched builds actually appear.
  • endoflife.date/php: a clear view of which PHP versions still receive security fixes, and until when.
  • composer audit and Dependabot: these cover your PHP packages, not the PHP binary itself, so use them alongside the sources above rather than instead of them.

Following sources is only half of it. Someone has to read them, decide what applies, and act, often within hours.

Why the team behind your site matters

There are many talented freelancers and small teams doing excellent work at modest prices, and price on its own says little about quality. The real question is not how much you paid to have your site built. It is who is responsible for it after launch.

Many sites are built, handed over and never touched again. The developer has moved on to the next project, the client assumes the hosting company handles updates, and the hosting company assumes the client does. Nobody is wrong exactly, but nobody is watching either. A release like this one shows the cost of that gap: a critical, unauthenticated vulnerability that needs a deliberate upgrade, a restart of the right processes and a check that it actually worked.

If you rely on an outside team, or are choosing one, these questions tell you quickly whether you are covered:

  1. Do you know which PHP version every one of my sites and servers runs right now?
  2. Who receives security advisories for my stack, and how quickly do you act on critical ones?
  3. Do I have a staging environment where patches are tested before production?
  4. Do you restart queue workers, Horizon and other background processes after a PHP upgrade?
  5. How will you tell me what was patched and when?
  6. What is the plan for moving off PHP versions that are end of life?

A good team will answer these without hesitation. If the answers are vague, it is worth fixing that before the next advisory, not after it.

We wrote about what an unpatched PHP server can turn into in our case study on removing a hidden PHP backdoor. The pattern is always the same: compromises rarely start with something exotic. They start with something that was known, fixable and left alone.


Need Someone Watching Your Laravel and PHP Servers?

We build, host and maintain Laravel and PHP applications for businesses in the UK, US, Middle East and beyond. Patching, monitoring and version upgrades are part of how we work, not an extra you have to remember to ask for. If you are not sure whether your servers were patched this week, we can check for you.

Talk to our team →

Tags

PHPLaravelLaravel ForgeSecurity PatchingCVE-2026-109618CVE-2026-109619Server Maintenance