PHP2Shell and the cost of not updating
On October 21, PHP shipped a critical security update. If your stack runs PHP, it should be applied by now. If it doesn't, keep reading anyway.
What happened
On October 20, the PHP project announced a security release for the following day, and public reports were already saying the flaws allowed remote code execution. On October 21, PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 came out, fixing two vulnerabilities: CVE-2026-109618 and CVE-2026-109619, together known as PHP2Shell. Both score 9.2 out of 10 on CVSS 4.0.
The scope is what makes them serious:
- Every PHP version from 5.4, released in March 2012, through 8.5.11 is affected. That is fourteen years of releases.
- They allow unauthenticated remote code execution on any installation that serves web requests: PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP or LiteSpeed.
- The bug lives in the interpreter, not in your application. Your framework, your CMS and the quality of your code don't help here: according to Rapid7, in some setups the attack works before a single line of application code runs.
- On October 26, CISA added both to its Known Exploited Vulnerabilities catalog (KEV) and gave US federal agencies until October 29 to fix them.
- Unit 42, Palo Alto Networks' research team, identified over 22.6 million exposed instances that are potentially vulnerable.
One detail that is easy to miss: installing the new version is not enough. You have to restart the processes that serve PHP (the PHP-FPM, Apache, FrankenPHP or LiteSpeed workers) and check that what answers in production really is the fixed version. Until the old process is restarted, the old code keeps running.
And it didn't end there. On October 23, PHP issued an extra advisory for a residual case, CVE-2026-115560, which the project says only affects unusual configurations. As of November 4 it is still unpatched: the fix ships with the next regular release, and in the meantime there is a published mitigation (see the CERT-EU advisory).
You wrote the 5%
When a team thinks about security, it thinks about its own code: form validation, permissions, that one query nobody reviewed. Fair enough. Now do the math on your own project. Underneath what you wrote there is a framework, dozens or hundreds of packages, a runtime, a web server and an operating system. Your code is a small slice of what actually runs in production; call it 5%. You imported the other 95%.
PHP2Shell makes the point uncomfortably clear: teams with spotless code ended up exposed because of a component they didn't write, don't review and, quite often, couldn't tell you the version of.
"If it works, don't touch it"
It is one of the most repeated lines in this industry, and one of the most expensive. It sounds prudent. In practice it is debt, and technical debt compounds.
Going from PHP 8.3 to 8.4 takes an afternoon. Going from 7.4 to 8.4 is a project: years of accumulated language changes, libraries that no longer support your version, and a few that no longer exist at all. You can plan that project on any given Tuesday. On the day a critical vulnerability drops, you don't have weeks. You have hours. And whoever is still on 7.4 that day doesn't have a patch to apply. They have a migration they kept putting off.
An unsupported runtime is a risk you accepted without signing anything
PHP 7.4 stopped getting security fixes on November 28, 2022; PHP 8.0 on November 26, 2023; PHP 8.1 on December 31, 2025. For PHP2Shell the project made an exception and published minimal source-level fixes for those three branches, aimed at people who build PHP themselves. There were no new releases. If your PHP comes from a distribution or a vendor with extended support, the fix may have reached you that way. But it was an exception, not a promise: those branches have no reason to get the next one. Patched or not, you still need to migrate.
How many sites are in that spot? According to W3Techs, as of November 4 PHP runs 69.1% of websites whose server-side language is known. Of those, 26.2% are still on PHP 7 and 7.6% on PHP 5. In other words, more than a third of the PHP web runs on major versions the project no longer maintains. And PHP 8.2, still supported today, stops getting fixes on December 31, 2026.
This isn't a PHP problem. Node.js 18 reached end of life on April 30, 2025, and Node.js 20 on April 30, 2026. Python 3.9 did on October 31, 2025. Nobody signed off on running unpatched software. The date just went by and nobody was looking at the calendar.
Automating the alert is not automating the update
Dependabot and Renovate are good tools. They watch your dependencies, tell you when there is a new version or a known vulnerability, and open a pull request ready for review. The trouble starts when those PRs pile up. With forty of them open, nobody looks, and the day a critical one arrives it gets buried among minor bumps to a date library. At that point the tool is decoration: it gives everyone the feeling that someone is on it, and no one is.
Not every advisory is an emergency (but you have to look to know)
Most security advisories are low severity, hit features you don't use, or sit in development dependencies that never reach production. Treating every one of them as a fire is the fastest way to get a team to stop reading them. But someone has to read them to tell the noise from the signal. PHP2Shell was critical, required no authentication, lived in the runtime and was being exploited. That doesn't get scheduled for next sprint.
Three things to do today
-
Audit your dependencies. Nearly every ecosystem has a way to do it: npm, Composer, pip, NuGet, Bundler, Cargo. Some build it into the package manager, others ship it as a separate tool. Most take under a minute:
npm audit # npm composer audit # Composer pip-audit # pip dotnet list package --vulnerable # NuGet bundle audit # Bundler cargo audit # Cargopip-audit,bundle audit(from the bundler-audit gem) andcargo auditare separate installs. The total count matters less than what the critical and high findings say. One caveat: an audit checks your packages, not your runtime. A clean report says nothing about whether your PHP, Node or Python version is still supported; that is step 2.For a second pair of eyes, give an AI like Claude or ChatGPT the list of your dependencies and their versions (what your
package.json,composer.json,requirements.txt,Gemfileor.csprojsays) and ask it to flag what is outdated or out of support. Just the list: no credentials, no private URLs, nothing internal. It helps you sort things out, but verify afterwards with the audit and the official sources, because the model may not know about last week's release. - Check your runtime version and its end-of-life date. PHP, Node, Python, .NET, Java, whatever you run. endoflife.date has nearly all of them in one place. If the date has passed, you have a project on your hands. If it passes in the next six months, you have one too.
- Count your open Dependabot or Renovate PRs. If there are more than three, block two hours this week to go through them. You don't need to merge them all; you need to know what's in there.
Keeping dependencies current is not glamorous, and it will never be the feature that makes the demo. There will be another critical vulnerability in something you imported; that part is not up for debate. What you do get to decide is how far behind it finds you. And if someone asks "how does this pay for itself?", the answer is easy: it costs a lot less than the alternative.
Sources
- Rapid7: CVE-2026-109618 and CVE-2026-109619 (scope, fixed versions, KEV listing)
- CISA: Critical Vulnerabilities in PHP Require Immediate Patching
- Google Cloud: Responding to core PHP vulnerabilities (affected versions back to 5.4)
- Unit 42 (Palo Alto Networks) (exposed instances)
- CERT-EU, Security Advisory 2026-018 (timeline and CVE-2026-115560)
- CISA KEV catalog (cisagov/kev-data) (added October 26, due October 29)
- PHP: supported versions and unsupported branches
- PHP: release archive (PHP 5.4, March 2012)
- W3Techs: PHP usage by version (data as of November 4, 2026)
- endoflife.date (end-of-life dates for PHP, Node.js and Python)
This piece deliberately leaves out any technical detail on how the flaws are exploited. If you need to mitigate, go to the official PHP advisory or the CERT-EU one.