Back to the blog
SecurityPHPDevOps

Critical PHP vulnerability: why you should update today

October 30, 2026·6 min read·Diego Horvatti

On October 21, the PHP team published an advisory with a title nobody wants to read: "Critical remote code execution vulnerabilities, update now". There are two flaws. Together, they let someone run code on your server without logging in. This critical PHP vulnerability applies to almost every installation that serves web requests. And on mod_php, the attack happens before a single line of your application runs.

Maybe you're thinking: "Diego, my stack is TypeScript and Bun, this isn't my problem". Hold on. I thought that too, for about two seconds. Then I remembered the client's WordPress, the old admin panel nobody dares to turn off and that VPS running a phpMyAdmin "just for emergencies".

What happened, in plain English

The official PHP announcement describes two different flaws. Both deal with how PHP manages memory and state between one request and the next.

CVE-2026-109618, out-of-memory corruption. When PHP runs out of memory while building the request's internal data, it stops halfway. Later, the cleanup routine looks at that half-built data and treats it all as valid. Invalid data treated as valid, inside the runtime, is the classic recipe for code execution.

CVE-2026-109619, stale global state. A piece of internal state that belongs to one request stays alive after its memory has been freed. The next request handled by the same worker can use that state before the normal startup cleans everything up. It's a use-after-free across requests.

The full technical details are in the GitHub advisories (GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp).

These are the fixed versions:

  • PHP 8.5.12
  • PHP 8.4.27
  • PHP 8.3.36
  • PHP 8.2.35

Who is exposed to this critical PHP vulnerability?

Short answer: almost everyone serving PHP over the web. The advisory mentions PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. The biggest risk is on mod_php, where an exploit has already been demonstrated with a single unauthenticated request.

That "before any application code runs" detail is what matters most. It means your framework won't save you. Your auth middleware won't save you. The application WAF, that clever if at the Laravel entry point, none of it even gets to run.

When the flaw is in the runtime, your nice application code never even gets consulted.

Then there's the case that worries me most: PHP 8.1 and older. The project no longer supports those versions. Given the severity, the security team published minimal source backports for 7.4, 8.0 and 8.1. But that only helps people who compile from source. If you installed through the package manager of an old distro, you need to check whether your provider (distro or LTS vendor) shipped the backport.

How to check and update now

Step one: find out what you have running. Sounds obvious, but a lot of people find forgotten PHP servers on exactly a day like this.

# CLI version (may differ from the one serving the web!)
php -v

# FPM version
php-fpm8.3 -v

# in a container
docker exec my-container php -v

Pay attention to the comment on the first command. I've seen a server with PHP 8.3 on the CLI and an FPM 8.1 serving the site, because someone installed both versions and forgot about one. Check what serves requests, not what shows up in the terminal.

A quick way to confirm through the application itself:

<?php
// add temporarily, open it and DELETE it right after
echo PHP_VERSION;

Then update through whatever path you use:

  • Linux distro: distributions got the patches before the disclosure. Run your normal system update and check that the package version changed.
  • Docker: change the image tag to the fixed version, rebuild and redeploy. If you use php:8.3-fpm without pinning the patch, a docker pull does it. But only if you actually pull the new image and recreate the container.
  • Shared hosting: open a ticket. Seriously. Ask for the exact version.

And restart every worker. PHP-FPM with an old process still alive keeps running old code, and the second flaw lives exactly in the state that survives between requests.

What if I can't update today?

The advisory itself is honest here: only updating truly fixes it. The measures below reduce known attack paths, but they don't make the installation safe. Treat them as a bandage to buy a few hours, not as a solution.

For the memory flaw (CVE-2026-109618):

; in the FPM pool or Apache config, where the application can't override it
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M
php_admin_value[upload_max_filesize] = 6M

The idea is to take away the attacker's control over when PHP runs out of memory. If the application needs uploads, the advisory suggests post_max_size = 32M, always with upload_max_filesize below that. It's also worth limiting body size, number of fields and multipart parts at the proxy.

Yes, memory_limit=-1 is a little scary. That's why the recommendation is to use a container or cgroup as the real limit, ideally killing only the affected worker. And one important detail: don't use RLIMIT_AS or RLIMIT_DATA instead, because they can cause exactly the allocation failure that triggers the bug.

For the global state flaw (CVE-2026-109619):

session.upload_progress.enabled = 0
; PHP 8.5 only:
fatal_error_backtraces = 0

This has to go in php.ini, the FPM pool or the server config. ini_set() and .user.ini won't work, because the attack happens before they're read. Restart every worker afterwards.

There's one more recommendation I found interesting: hiding errors doesn't help. Using @, display_errors=0 or tweaking error_reporting closes nothing. What helps is removing invalid or deprecated per-request settings that generate diagnostics before startup, and fixing fatal errors and timeouts an attacker can trigger.

Why this matters even if you don't write PHP

PHP still runs a huge slice of the web. If you're a full stack dev working with clients, the odds of having a WordPress, a Magento or a legacy system in your lap are high. Often you weren't even the one who deployed it. But you're the one who gets the call when the site starts redirecting to a casino.

The architecture lesson also applies to the Node and Bun world. The second flaw comes from worker reuse: the same process handles many requests and something leaks from one to another. Anyone writing servers in Node lives with this every day. A module-scoped variable, an in-memory cache without a per-user key, and that's it: data from one request shows up in another. In PHP the bug is in the runtime. In our case, it's usually in our own code.

// the "homemade" version of the bug, in any JS server
let currentUser: User | null = null // shared global state

app.get('/profile', async (req) => {
  currentUser = await auth(req) // a concurrent request can overwrite it
  return render(currentUser)
})

If you have something like this, it's worth reviewing today too.

My take

The PHP team did the right thing. They warned distros first, shipped releases for every supported branch, backported to dead versions and listed mitigations with the honesty to say "this doesn't fix it". Few people write security advisories this useful.

The real problem isn't PHP. It's the server nobody remembers exists. My rule is simple: if it has no owner, shut it down. If it has an owner, update it this week, not next sprint. Server inventory is boring until the day it saves you.

If you want to see how I handle deploys and updates in my projects, take a look at some of the projects I maintain.

LinkedIn summary

Your stack can be 100% TypeScript and there can still be a vulnerable PHP server with your name on the on-call list.

On the 21st, PHP disclosed two flaws that let someone run code on the server without logging in. On mod_php, the attack happens before a single line of the application runs.

In other words: framework, middleware and authentication never even get a say.

Patch today: 8.5.12, 8.4.27, 8.3.36 or 8.2.35. Check the version that serves requests, not the one in your terminal, and restart every worker.

My rule for forgotten servers is simple: if it has no owner, shut it down. If it has an owner, update it this week.

I wrote the full step by step, with the mitigations and the parallel with Node and Bun. If you have an old WordPress to look after, the link is in the comments.

#PHP #InfoSec #DevOps #WebDevelopment #FullStack