PHP2Shell Explained, How to Fix it?: CVE-2026-109618 and 109619

PHP2Shell Explained, How to Fix it?: CVE-2026-109618 and 109619

Before sleeping on Tuesday I opened terminal, logged into my small test server and typed php -v. The answer was 8.3.6. That's all I wanted to know at that moment, and I'll explain later why that number alone doesn't tell you much.

The reason was a short notice on the PHP mailing list. The PHP security team said a security release would come on Wednesday, October 21, at 14:00 UTC (that’s 7:30 in the evening in India), and it would fix two vulnerabilities, both scored 9.2 out of 10. No names, no details, only a line asking everybody to get ready to update. PrivateDevOps pointed out that the team rarely gives advance notice at all, so doing it for two bugs at once got people’s attention fast.

And then the details leaked.

What PHP2Shell actually is

PHP is a programming language, and a big part of the web runs on it. Malware News describes it as the language behind WordPress, Drupal, Magento, Laravel and many custom apps. If you run a WordPress blog, or your shop’s website was built by a freelancer some years back, there’s a good chance PHP is working behind the scenes right now.

So, the bugs. There are two of them, tracked as CVE-2026–109618 and CVE-2026–109619. A CVE number is just an ID so everyone can talk about the same bug. The nickname PHP2Shell didn’t come from the PHP team, researchers gave it. Both bugs carry a CVSS v4.0 score of 9.2, which the PHP security team set itself. CVSS is a 0 to 10 scale for how dangerous a bug is, and anything from 9.0 up lands in the critical band. Some early leaked posts said 10.0, but the official number is 9.2, so that’s the one I’m using.

The scary label on both is remote code execution, or RCE. In simple words, a person sitting far away can make your server run commands that you never wrote. Think of a stranger typing on your server’s keyboard, only they’re doing it over the internet. Security firms like SecureLayer7 also describe these bugs as unauthenticated, which means the attacker doesn’t need an account or password on your site.

No login, no stolen password.

…and that last part is what moves a bug from “annoying, will patch next week” to “drop everything.” Normally an attacker has to trick someone first, or find a weak password. Here, if the early write-ups are right, they only need to reach your server over the network.

How the bug works, in simple words

PHP has a feature called session upload progress. When somebody uploads a big file, a website can show a progress bar. To do that, PHP keeps a running count of how many bytes have arrived, and it stores that count in the session, which is the server’s short-term memory of one visitor. The setting is called session.upload_progress.enabled, and a lab write-up on DEV Community says it's been switched on by default since PHP 5.4, which came out in 2012. So most servers have it on without anyone ever choosing it.

According to an early analysis from Upwind, both bugs sit in the code that handles this feature, in a function named php_session_rfc1867_callback. While an upload is running, PHP remembers where two of those counters live in memory. Now say a second request arrives and makes PHP reload the session. The old memory gets cleaned up, but PHP still holds the old addresses and keeps using them. Security people call this a use-after-free bug.

Here’s one way to picture it. You check out of a hotel room and hand back the key. The hotel gives the room to a new guest, but you kept a copy of the key and nobody knows. When you walk in again, you’re touching things that belong to someone else. In a typical attack of this kind, the attacker is the one who decides what’s sitting inside that room at the moment PHP walks back in. If they place the right data there, PHP can end up following instructions it should never follow, and that’s how a memory mistake turns into code running on the server. This is mostly accurate, though I’m oversimplifying. The real mechanics involve something called hash tables, and I’ll admit that part went over my head when I read the write-ups. What matters for you is the result and not the mechanism itself.

I should be clear about where all this comes from. PHP hadn’t published technical details when I checked. The description above is from Upwind and Phoenix Security, who both pointed to a purported proof of concept that was going around, so treat it as a strong lead and not as official word.

One public research repo on GitHub, from a user named ikow, also lists other attack paths, and at least one of them needs the target website to have a second weakness, a file inclusion bug. If that’s right, not every site is equally easy to break. I couldn’t verify this claim myself.

How it came out

The finder is still unnamed. PHP’s notice didn’t credit anyone, and none of the write-ups I read did either, so I won’t guess. What we do know is how the story became public.

On Tuesday, October 20, the notice went out on PHP’s announcement list. Tenable says the CVE numbers started circulating on Hacker News and social media the same day, even though PHP’s notice hadn’t named them. The security firm watchTowr then said the leaked information was about real, embargoed bugs, and that it couldn’t share more. After that, researcher Kevin Beaumont posted the expected fixed version numbers and added his own guess about why things moved so fast: security vendors who got advance notice told their customers, details spread, and PHP probably had to bring the release forward. That’s his opinion, not something PHP confirmed. PHP’s notice had already said it could release early if details got out or attacks showed up in the wild, according to The Hacker News.

Researcher Will Dormann also posted that a group called Calif may have a proof of concept named php2shell that works against WordPress. I haven’t been able to confirm that one, so take it with some salt.

I spent more than an hour on Tuesday night reading blog posts that all disagreed with each other. One said only PHP 8 was affected. Another said everything from PHP 5.4 onward. Beaumont said the bugs go back to versions from 2004. They can’t all be right, and PHP itself hadn’t said which one was. My lean is simple: until PHP publishes its own list, assume old versions are affected and won’t get a fix. If I’m wrong, I lose nothing. If I’m right and I ignored it, I lose a server.

Who’s at risk, and what could happen

Start with the numbers. Mallory, a security company, counted about 884,000 internet-facing hosts that told Shodan they run PHP 8.1 or older on October 20. The Hacker News reports that this is 59% of the roughly 1.5 million hosts that showed any PHP version at all. Many servers hide their version, so the real count of PHP servers is bigger, though I don’t know by how much. Beaumont called this one of the biggest vulnerabilities in years. That’s his judgment, but the numbers don’t make me want to argue.

Which versions get a fix? The expected ones are PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. At the time of writing I couldn’t open any PHP page that confirmed these numbers, and they come from Beaumont and other trackers, so check php.net before you rely on them. Everything older, meaning 8.1, 8.0, 7.x and 5.x, is end-of-life and won’t get an official fix.

This is where it gets ugly in real life. In my experience, old PHP sites sit on servers because the developer who built them left years ago and nobody dares to touch the thing. A school website, a small shop’s order form, some internal tool for a warehouse. They run PHP 5.6 or 7.2, they work fine, so they never get updated. Those are exactly the sites with no patch coming.

If you only run a WordPress blog, one more thing matters. The bug is in PHP, the layer underneath WordPress. So updating WordPress, your theme or your plugins won’t fix it. The fix has to happen where PHP itself is installed, which means your hosting company or your server.

What can an attacker do once code runs? They run it as the same user your website runs as. That’s less than full control of the whole machine, but it’s still a lot. They can read your site’s config file, which usually holds the database password. They can copy customer records, orders and email addresses. They can plant a hidden backdoor, called a webshell, so they can come back later even after you patch. They can change your pages, send spam from your server, mine cryptocurrency, or lock your files and ask for ransom. On shared hosting, they might even reach other people’s sites on the same machine.

That webshell point is the one people forget. A patch closes the door, but it doesn’t remove someone who’s already inside.

What if you don’t own a website at all? You’re still in the picture, just further back. Your name, email and order history sit on other people’s servers, and some of those run PHP. You can’t patch their machines, but you can watch for emails from sites you use about a security incident, and when one arrives, change that site’s password quickly and don’t reuse it anywhere else. If a password manager flags a site as breached, take that seriously. It’s a boring habit, and it’s the only part of this story that’s fully in your hands.

Small businesses are the group I worry about most. A big company has a security team that read the PHP notice on Tuesday and started a patch plan before the details even leaked. A five-person shop with a rented server often has nobody who knows the PHP version, and the freelancer who set it up now works somewhere else. If that’s you, the simplest move is one email to your hosting company asking two things: which PHP version your site runs, and when they’ll move you to a fixed one. Ask for the answer in writing, and keep it.

As of the reports I read on Wednesday morning, nobody had confirmed attacks in the wild. That can change in hours once technical details are public, so I wouldn’t use it as a reason to wait.

What to do right now

First, find out which PHP your website really uses. It will only take a minute. On a server you control, run this:

php -v

Careful, though. The PHP you get on the command line and the PHP your website runs can be two separate installs, and people get fooled by this. If you can’t log in to a server, look at the PHP version page in your hosting panel (cPanel has one), or ask your host’s support.

Second, patch as soon as the fix is out. On a Linux server you manage, it’s usually the normal update commands and then a restart of PHP:

sudo apt update && sudo apt upgrade
sudo systemctl restart php8.3-fpm

The service name changes with your PHP version, so use your own.

Now, my 8.3.6 problem. Most Linux servers don’t run PHP straight from php.net. Ubuntu, Debian and others take the upstream fix and put it inside their own build without changing the version number. PatchMon’s guide lists Ubuntu 24.04 LTS as shipping 8.3.6 and Debian 13 as shipping 8.4.24, for example. So a number that looks old can already be patched, and a number that looks fine can still be vulnerable. Look for your distro’s security notice for these two CVE IDs, and don’t depend on the number alone.

On managed WordPress hosting the host usually patches for you, but send them one message to be sure. On cPanel-style hosting, switch the site to a fixed PHP version when it shows up. With Docker, rebuild your image after a fixed tag is published. With XAMPP or similar tools on Windows, download the new build.

Third, a stopgap, only if the patch isn’t available to you yet. You can switch off the feature involved. In php.ini or a .user.inifile, set this, then reload PHP-FPM:

session.upload_progress.enabled = 0

A post on daily.dev also has tested configs for nginx, Apache, Caddy, lighttpd and FrankenPHP that block multipart requests for apps that have no uploads, since PHP still reads the whole multipart body even when file uploads are off.

But don’t feel safe after this. PHP core developer Gina Peter Banyard said patching is the only real fix, and Joe Ferguson, release manager for PHP 8.6, said turning off that setting wouldn’t save you. Phoenix Security says it covers only one of the two suspected paths. So it’s a bandage, and I’d use it only to buy a few hours.

Fourth, if you’re on PHP 8.1 or older, no official fix is coming, and the real answer is moving to a supported version. I’d pick 8.4 or 8.5. PHP 8.2 still gets security fixes, but only until December 31, 2026, which is a short runway, so I’d skip it for anything new. If you can’t upgrade today, put a firewall in front, block multipart requests where you don’t need them, or take the site offline until you can. A site that’s down for a day is better than a site with a backdoor.

Fifth, after patching, look for signs of a break-in. Check for new PHP files in upload folders, strange sess_ files in your session folder, changed files you didn't touch, and odd multipart POST requests in your access logs going to pages that have no upload form. The leak has been public since October 20, so any server that was exposed since then deserves a look. If you find anything odd, change the database password and any API keys stored on that machine, and talk to a security person.

Where I land

Patch today if the fix is out when you read this. Waiting for proof of attacks before patching is the wrong order, because by the time there’s proof, it’s late. And the ini setting is a bandage, so I wouldn’t call a site safe because of it.

Two things are still open as I write. I couldn’t confirm that PHP’s release is live yet, and the fixed version numbers I used come from trackers, not from PHP. The official list will be on the news page at php.net, so check there before you trust mine.

Me, I’m going back to my test server now. The 8.3.6 on it came from Ubuntu, so I’ll look for Ubuntu’s notice on these two CVEs and update from there. Go check yours. It’s a two-minute job.

Post a Comment

Previous Post Next Post