Skip to content
Go back

PHP2Shell and the Case for Public Sites That Don't Run Code

Published:

Last Wednesday, government agencies and companies around the world took websites offline rather than leave them exposed. The cause was PHP2Shell, a pair of critical bugs in PHP itself, and it’s a good moment to ask a question I think more people should be asking: why is a public website running code at all?

What actually happened

The two vulnerabilities, CVE-2026-109618 and CVE-2026-109619, both scored 9.2 out of 10. Both can lead to an unauthenticated attacker running code on a server that handles PHP requests. PHP shipped fixes on 21 October (8.5.12, 8.4.27, 8.3.36 and 8.2.35), after details leaked ahead of the planned disclosure. Amazon then told defenders to look for exploitation as early as 17 October đź”—, four days before the patches existed.

The picture has been mixed. On 22 October, Sansec said mass exploitation looked less likely than first feared, because the public exploits didn’t work against a default PHP install and needed specific knowledge of the target. Since then, TechCrunch has reported that Trail of Bits had working exploits by late Friday and that Cloudflare’s CEO has seen a huge number of exploit attempts, though there were still no signs of mass exploitation as of 24 October. “Not mass compromise yet” isn’t a comfortable place to be when the bug is in the language runtime itself. The UK’s NCSC called it critical 🔗, said all PHP versions are affected, and told organisations that can’t patch or mitigate quickly to consider taking the system offline until they can.

That’s the part that stuck with me. Normally the advice is to keep your plugins updated and use strong passwords. Here, Datadog’s analysis 🔗 found application-level authentication can’t block an attack, and the config workarounds that were circulating don’t fully protect you. You could have a perfectly maintained site and still be exposed until your host patched. And if you’re on an older branch, there may not be an official fix at all: PHP’s own project has no fixed release for 8.1 or older, only source patches for 7.4, 8.0 and 8.1, so you’re relying on a distribution or vendor backport, or an upgrade you may not have planned for.

This isn’t really a PHP problem

I don’t want this to turn into PHP bashing. Log4Shell was Java. The PHP-CGI bug from 2024 was a different flaw in the same ecosystem. Every language has its bad week.

The real issue is the model. On a traditional dynamic site, every single page view runs code on a server you’re responsible for. A request comes in, the server executes something, queries a database, and builds the page. That’s attack surface on every visit, and it’s there even when the site is a brochure that changes twice a month.

What a static site does differently

A static site builds its pages in advance. A visitor asks for a page and gets a file from a CDN. There’s no PHP, no database and no admin login sitting on the public domain.

So when a bug like PHP2Shell lands, there’s nothing for it to land on. No runtime is processing requests, so there’s nothing to inject code into. Does that mean it’s secure? Not by magic, but the whole category of “attacker makes the server run something” mostly goes away.

This is where a headless CMS fits in nicely. Editors write content in a separate tool, and when someone publishes, the site is rebuilt and deployed. I’d reach for Sanity, but the idea doesn’t depend on it. Contentful, Storyblok or a headless WordPress would all work the same way. What matters is that the editing side and the public side are separate. With a build like that, the thing visitors hit isn’t connected to the CMS or a database at all, so there’s no path from the public site back to anything valuable.

A build isn’t the only way to use a headless CMS though. With Sanity, for example, querying the API directly is just as standard, and its docs recommend the cached, read-only API CDN for fetching content from a browser. That’s still a very different shape from PHP2Shell. The page itself is still static files, and the request for content goes to a read-only endpoint on a managed service rather than a runtime on a server you look after, so there’s much less there to attack. The trade-off is a dependency at request time, and the uncached API is the one that always gives you the freshest content, so the cached one trades a little freshness for speed. And if you fetch content from a server-rendered app instead of the browser, you’re running a server again, which puts it back on your patch list.

Is it bulletproof? No

Static sites aren’t immune, and I’d be doing you a disservice if I said they were.

The build pipeline still runs Node and a pile of npm dependencies, so supply chain risk is real. Anything dynamic, like a contact form or search, needs a service somewhere, and that service is code. The hosting platform runs software too.

Headless WordPress is the awkward one here. It still runs PHP, so PHP2Shell applies to the WordPress side exactly as it does to any other site, and it still needs patching. What you gain is that it’s no longer the public face. If the site is built statically, only your editors and the build need to reach it, so it can sit behind a login or an IP allowlist instead of being open to every visitor and every scanner. That’s a real improvement, but it isn’t the same as not running PHP at all.

The difference is where the risk sits and who deals with it. The build runs on your terms, isn’t exposed to the internet, and can be locked down. The hosting layer is patched by a team whose full-time job is exactly that. And the part you do own is small enough to actually reason about.

There’s also an honest “when this is overkill” in reverse: if you’re building something with user logins, user-generated content or a big shop, you need a dynamic backend, and that’s fine. Most business websites aren’t that. They’re a handful of pages, a blog and a form, and they’ve been running a full server-side stack out of habit.

Where I’ve landed

Patching quickly is still the right call when something like this drops, and anyone running PHP should have done it by now. But I’d rather run a site that doesn’t need an urgent patch than one that’s very good at getting them.

If your public site only needs to show content, it shouldn’t have to execute anything to do it.


Share this post on:
Matt Thomas

Matt Thomas

Azure Solutions Architect at Howden · Microsoft Certified AZ-305


Next Post
Moving CI to GitHub but Keeping CD in Azure DevOps