DEV Community

Cover image for What Developers Need to Know About the PHP Flaw That Took Websites Offline
Renato Silva
Renato Silva

Posted on

What Developers Need to Know About the PHP Flaw That Took Websites Offline

If you opened a government website this week and found a maintenance page, there's a good chance PHP was the reason.

On 21 October 2026, the PHP team shipped emergency releases for two critical vulnerabilities in the language's core, now known as PHP2Shell (CVE-2026-109618 and CVE-2026-109619). Within hours, governments in Finland, the Netherlands, Germany, Belgium, France and Canada had taken public websites offline as a precaution while they patched.

I don't write PHP day to day, but a lot of the systems around me do: WordPress marketing sites, internal tools, legacy admin panels nobody remembers deploying. If that sounds like your company too, this post is for you.

TL;DR

  • Two unauthenticated remote code execution bugs in PHP itself, not in a framework or plugin.
  • Both rated CVSS v4.0 9.2 (Critical).
  • Fixed in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Anything older on those branches is vulnerable.
  • PHP 8.1 and older get no official fix.
  • Exploitation was reported before and after the release. Patch now, then restart every PHP worker.

What happened: a short timeline

  • 20 October – Details of the two vulnerabilities leaked online before coordinated disclosure, and before any patch existed.
  • 21 October, 14:00 UTC – The PHP team pulled the release forward (it had been planned for 22 October) and shipped fixes for all four supported branches.
  • 21–22 October – National cybersecurity agencies in Europe, the UK, Australia and Japan told organisations to update immediately or take sites offline until they could. Security firms reported exploitation happening at scale.

One more detail made headlines: the bugs were found with the help of AI. Wiz Research is credited with the discovery, and OpenAI says its models helped. The underlying code had been sitting in PHP for more than a decade, with the earliest affected path dating back to PHP 5.4.0.

Why this one is different

Most PHP security incidents you've read about live in the application layer: a vulnerable WordPress plugin, an unsafe unserialize() call in someone's code, a misconfigured upload form.

PHP2Shell lives below your code. Security researchers who reproduced it confirmed that the malicious request is processed by the PHP engine before any application code runs. That means:

  • Your login middleware doesn't help.
  • Your framework's CSRF protection doesn't help.
  • "But our app doesn't do anything with uploads" doesn't help.

If PHP is serving web requests, it's in scope.

The two bugs in plain English

Both bugs come from the same family: PHP leaving memory in an inconsistent state after something goes wrong mid-request, and then trusting that state later. CrowdStrike classifies both as CWE-824, access of an uninitialized pointer.

CVE-2026-109618 – "RCE via OOM corruption"

If PHP runs out of memory while it's still setting up internal request data, the request gets interrupted with that data only half built. The cleanup routine at the end of the request then treats the half-built data as valid. Corrupt data handed to cleanup code is the path to code execution.

CVE-2026-109619 – "RCE via stale global state"

This one is a use-after-free that spans requests. A fatal error can leave a long-lived PHP worker holding pointers into memory that belonged to a request that has already finished and been freed. If the same worker picks up another request, it can touch that stale state before PHP's normal initialization resets it.

Public analyses tie this one to the session.upload_progress feature, which is on by default and kicks in on multipart POST requests before your script starts.

If you come from .NET or Node, a rough mental model: imagine a static field in a long-running process that still points at an object from a previous request, after that object has been disposed. Now imagine the runtime itself made that mistake, not your code.

Am I affected?

Check the version every PHP process is actually running, not just what your Dockerfile says:

php -v
Enter fullscreen mode Exit fullscreen mode

For PHP-FPM, check the FPM binary too, as it can differ from the CLI:

php-fpm -v
# or, depending on your distro
php-fpm8.3 -v
Enter fullscreen mode Exit fullscreen mode

Then compare:

Branch Vulnerable First fixed release
8.5 below 8.5.12 8.5.12
8.4 below 8.4.27 8.4.27
8.3 below 8.3.36 8.3.36
8.2 below 8.2.35 8.2.35
8.1 and older all no upstream fix

The PHP team says all installations serving web requests are at risk. That includes PHP-FPM behind nginx, Apache with mod_php, and other supported server setups.

How to fix it

1. Upgrade

Move to the patched release for your branch. Some common paths:

Docker: rebuild against the new official image tag, and don't trust a cached base layer.

FROM php:8.3.36-fpm
Enter fullscreen mode Exit fullscreen mode
docker build --pull --no-cache -t my-app .
Enter fullscreen mode Exit fullscreen mode

Debian/Ubuntu or RHEL-family: install the update from your distro or PHP repository (for example Ondřej Surý's PPA or Remi's repo), then confirm the version.

Managed hosting: ask your provider to confirm the fix is installed, not just scheduled.

2. Restart every worker

This is the step people skip. Installing a new binary does nothing for FPM pools or Apache children that are still running the old one, and CVE-2026-109619 lives precisely in long-lived workers.

sudo systemctl restart php8.3-fpm
sudo systemctl restart apache2   # if you use mod_php
Enter fullscreen mode Exit fullscreen mode

Then run php -v and check a phpinfo() page (and remove it afterwards!) to confirm the version actually serving traffic.

3. Can't patch today? Apply the mitigations

The PHP advisories list temporary mitigations. Treat them as a bridge to patching, not a replacement:

For CVE-2026-109619:

; php.ini
session.upload_progress.enabled = 0

; PHP 8.5 only
fatal_error_backtraces = 0
Enter fullscreen mode Exit fullscreen mode

For CVE-2026-109618: set memory_limit = -1 at the administrator level, so applications can't override it.

; php-fpm pool config, e.g. www.conf
php_admin_value[memory_limit] = -1
Enter fullscreen mode Exit fullscreen mode

Yes, that removes PHP's per-request memory cap, which is uncomfortable. Pair it with request-size limits on your web server or load balancer, and a memory limit on the container or process, so a single request still can't take the box down.

If you can do neither, the UK's NCSC advice is blunt: consider taking the system offline until it can be fixed. That's exactly what many governments did.

4. Find the PHP you forgot about

This is the longer-term risk. Look beyond your main apps:

  • Old marketing sites and landing pages
  • Internal admin tools and dashboards
  • Devices with PHP-based web interfaces (routers, NAS boxes, appliances)
  • Staging and demo environments that are still reachable from the internet

What if I'm on PHP 8.1 or older?

The PHP project doesn't support 8.1 and earlier anymore, so there is no official patch. Your realistic options are:

  1. Upgrade to a supported branch (8.2 or newer).
  2. Use a backported fix from your Linux distribution or a commercial long-term-support vendor.
  3. Apply the mitigations above and plan the upgrade now.

This isn't a small group. One estimate counted roughly 884,000 internet-facing hosts advertising an end-of-life PHP version.

Also note: PHP 8.2 only receives security fixes until 31 December 2026. If you're upgrading anyway, it's worth skipping ahead.

Lessons for the rest of us

A few takeaways that apply whatever your stack is:

  1. Know your inventory. Taking every site offline "just in case" is what happens when nobody can quickly answer "where do we run PHP?". A software bill of materials pays for itself on days like this.
  2. Patching isn't done until the process restarts. Long-running workers in any runtime (.NET, Node, Java, PHP-FPM) keep old code in memory.
  3. Runtime bugs bypass app-level security. Defence in depth (WAF rules, network isolation, least privilege for the web user) is what limits the blast radius when the platform itself breaks.
  4. End-of-life is a security decision. "It still works" stops being true the day a bug like this lands.
  5. AI-assisted bug hunting is real now. Decade-old bugs in core runtimes are being found faster, by defenders and attackers. Expect more emergency releases, and keep your upgrade path short.

Have you had to patch PHP this week? I'd like to hear how it went, especially if you found PHP running somewhere you didn't expect. Let me know in the comments.

Top comments (0)