PHP2Shell: What We Checked, What We Fixed, and What We Learned
Reading time: ~ 3 minutes
On Tuesday, October 20, the PHP project gave everyone a day's notice that a security release was coming for two critical vulnerabilities. On Wednesday, the fixes landed.
The vulnerabilities, now known as PHP2Shell, are tracked as CVE-2026-109618 and CVE-2026-109619. Both are rated 9.2 out of 10, and both can allow unauthenticated remote code execution. In plain terms, someone on the internet could take control of an affected server with a single crafted request, before any of the application's own code even runs.
Most of the applications we support at Planet Argon are built on Ruby on Rails, which isn't affected. But PHP has a way of showing up where people don't expect it: a company blog, a marketing site, a content management system running alongside the main application. So we spent the day finding out where it was.
Most of the work was checking
Most of the applications we work on weren't impacted because they don't have WordPress blogs or PHP anywhere in the app. But a few did.
One application needed a same-day upgrade, one needed a temporary safety net, and a few got light follow-up work.
Ideally, that's what a security day looks like: a lot of checking and a short list of fixes. When the list is short, it's usually because the work was done months earlier.
The one that needed real work
One client runs a Laravel-based content management system on PHP 8.1. PHP 8.1 reached end of life at the end of 2025, so the PHP project no longer publishes official releases for it. There was no 8.1 patch to install.
So the fix became a version upgrade, the same day. We moved the application to PHP 8.2.35, the patched release on the oldest branch PHP still supports.
There was one snag. The official Docker image for 8.2.35 hadn't been published yet. Rather than wait, the team built the image from PHP's official build recipe, swapping in the new version. They kept the standard checks that verify the download (checksum and signature), and left extensions and configuration unchanged.
Then we tested it:
- Locally: the image built cleanly, extensions loaded, and the application's install and setup steps ran without errors.
- In the staging environment: the app, its background worker, and its admin all confirmed running 8.2.35.
- One broken feature: WebP image uploads failed. Before calling it a regression, we checked the old version. It failed there too, because WebP support had never been built in. The upgrade didn't cause it, and it's now on the list.
Then it went out to production. Fix applied!
When you can't upgrade today
Not every team can ship a PHP upgrade on a few hours' notice. For another client, we turned on Cloudflare's web application firewall (WAF) protection as a stopgap. Cloudflare had been working with the PHP team ahead of the announcement, and had rules blocking known PHP2Shell attack traffic live about nine hours before the vulnerabilities went public.
A firewall rule is a safety net, not a fix. Cloudflare says so itself: patch PHP as soon as possible and keep the firewall on as an extra layer. That's the plan for this client too. But for now, we applied a band-aid.
What happens next
Patching was the first step. The follow-up work is already underway:
- Extra hardening on the public-facing side of the upgraded application, based on the mitigations the PHP team published.
- Cleanup: switching to the official Docker image once it's published, and clearing out new deprecation warnings that came with 8.2.
- Planning the next upgrade. PHP 8.2 reaches end of life on December 31, 2026. An application still on 8.2 after that date will be right back where this client was this week: the next vulnerability arrives, and there's no patch to install.
What we'd recommend
The patch is only quick if you're on a supported version. For applications on supported PHP, this week was a routine update. For the one on 8.1, it was a same-day upgrade project. Same vulnerability, very different day, and the difference was decided long before October 21.
Know where your PHP lives. Plenty of teams don't think of themselves as running PHP. Check the blog, the marketing site, the CMS, and anything a vendor set up years ago.
Have a stop gap you can turn on. A firewall layer like Cloudflare's buys time. It doesn't replace the upgrade, but it keeps a hard day from becoming a dangerous one.
Look up your end-of-life dates now. PHP 8.2 ends December 31, 2026. The same question applies to every language and framework your application depends on.
Staying current is how proven software keeps going. We talk a lot about giving existing applications a second act. That doesn't mean leaving them alone. Keeping the language and framework current is the routine work that lets a fix like this go out in an afternoon instead of turning into a scramble.
If you're on PHP 8.1 or 8.2
If your application runs on PHP 8.1 or older, it didn't get an official release this week. If it's on 8.2, it has until the end of the year. Either way, we're happy to help you plan an upgrade, with a firewall stopgap in place if you need time. Let's talk.