This article first appeared on Medium: https://medium.com/@r3dtuxedo/php2shell-patch-today-then-find-the-php-you-forgot-dd590977c842
One engine, a lot of servers. The fix is out; the work now is finding them all.
TL;DR
• PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 fix two critical bugs in PHP itself (CVE-2026-109618 and CVE-2026-109619, nicknamed PHP2Shell). They can allow unauthenticated remote code execution on servers that handle web requests. Your own code doesn’t need to be buggy. Update, then restart every PHP worker.
• php -v doesn't settle it. Distros backport fixes into old version numbers, the CLI may not be what serves your site, and a container is only patched after you rebuild it.
• Most public proof-of-concept repos don’t work, and running strangers’ exploit code is a risk in itself. Check versions and packages instead. A coding agent is good at that: it can list every PHP version across your repos, Dockerfiles and CI, and open the patch PRs for you to review
On Wednesday 21 October, at 14:00 UTC, the PHP project shipped emergency releases for every supported branch. The two bugs behind them sit in how PHP cleans up memory when a request goes wrong. That makes them unusual: this isn’t a WordPress plugin or a framework bug. It’s the engine underneath all of them.
CISA put out an alert the same day, and the UK’s NCSC told organisations to update or take affected systems offline. AWS says the bugs are now “broadly exploited in the wild”. So this is a patch-today week, not a read-about-it-later week.
What broke, and who’s affected
Both bugs come from how PHP handles fatal errors, especially running out of memory, partway through a request. The request ends, but some of PHP’s internal state is left behind in a broken form. A later request on the same worker can then pick that state up, which can lead to memory corruption and code execution. php.net calls the first “RCE via OOM corruption” (CVE-2026-109618) and the second “RCE via stale global state” (CVE-2026-109619). Wiz adds that the same family of bugs can also leak a worker’s memory, including other requests’ passwords and tokens.
php.net’s advisory says who is at risk: “all PHP installations serving web requests, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed.” It rates mod_php as the highest risk, because there the attack can run before any application code does. Wiz, one of the teams that reported the bugs, says it ran code without logging in on the stock WordPress, Drupal and Joomla container images, and that “even a simple ‘Hello World’ application running on an affected PHP version can be vulnerable”.
This isn’t a bug in your app. It’s in the engine underneath all of them, so your code being clean doesn’t help
The PHP project scores both at 9.2 on CVSS v4. NVD has since added its own CVSS 3.1 score of 9.8. Here is what to run, by branch:
Fixed releases by branch, per php.net, 21 Oct 2026. Older branches depend on your vendor.
NVD’s record only lists the supported branches, but Wiz and Docker both say every version back to 5.4 is affected by at least one of the bugs. If you’re on something old, assume you’re in.
Two years of a stalled fix, then five days of leaks, rules and releases.
Patch now, and check it actually took
The question that matters is who builds the PHP you run. Only PHP built from php.net source reliably reports one of the fixed version numbers. Everyone else may be fixed under a different number.
Start with who builds your PHP. The version string only means one thing for php.net builds.
These are the read-only checks. None of them touch anything:
php -v # the CLI, which may not be what serves your site
php-fpm8.3 -v # or php-fpm -v; the binary name varies by distro
dpkg -l 'php*' | grep '^ii' # Debian, Ubuntu
rpm -qa 'php*' # RHEL, Fedora, SUSE
apk info -v | grep '^php' # Alpine
docker run --rm your/image:tag php -v
On distros, the version number can look old and still be fixed. Ubuntu 24.04’s fix is php8.3 8.3.6-0ubuntu0.24.04.13, which php -v reports as 8.3.6. So compare the full package version with your distro's tracker:
Fixed distro builds, per the Ubuntu and Debian trackers on 22 Oct 2026. The version string alone can look unpatched.
After the update, restart every worker. A running PHP-FPM pool or Apache process keeps the old code in memory until it’s restarted: sudo systemctl restart php8.3-fpm (or apache2, httpd, frankenphp, lsws). Then check that the master process started after the update, for example with ps -o lstart,cmd -C php-fpm8.3.
Containers. The Docker Official Images had the fixed tags on Docker Hub by the evening of 21 October (UTC). That doesn’t help a running container. Rebuild with docker build --pull, redeploy, and check the image you actually run, not the one you meant to run. Fixed upstream tags only reach you through a rebuild.
Managed hosting. If someone else runs PHP for you, it’s their patch. On 22 October a third-party tracker of host status pages listed Kinsta, Cloudways and Pantheon as patched and several others as still rolling out. Check yours, and ask for a date or a build, not just “you’re safe”.
If you can’t update today. php.net lists partial measures, and is clear that none of them make you safe. They include session.upload_progress.enabled=0 set in php.ini or the FPM pool (not via ini_set()), a low post_max_size, and on 8.5, fatal_error_backtraces=0. Restart every worker after any change. Hiding errors does nothing. A WAF in front helps: Cloudflare turned on rules for all plans, Free included, early on 21 October. CISA's advice for anything that can't be patched, including 8.1 and older, is blunter: take it offline until it can be.
How AI found it, and what that changes
The first sign of the out-of-memory problem appeared in 2024, during an external audit funded by Germany’s Sovereign Tech Agency. A PHP core developer noticed it, but nobody found a way to exploit it, and the competing fixes all broke something. The PHP Foundation’s own post calls the resulting two-year delay “a structural failure”.
What changed this year was AI-assisted research. According to the PHP Foundation, Calif reported an unconditional remote code execution on 11 August as part of OpenAI’s Patch the Planet programme. OpenAI says Calif used GPT-5.6 Sol, and OpenAI reported the same root cause independently. Wiz reported further paths on 24 August; it says it used Wiz Atlas, Gemini 4 Argon and GPT-5.6 Sol, with Argon contributing most. On the receiving end, the PHP Foundation says it used AI models from Anthropic and OpenAI to help validate the reports.
When three teams with AI help find the same bug in a few weeks, assume someone else can too
Three things follow from that.
Finding is getting cheap; fixing isn’t. The PHP security team says it has published 15 CVEs since 1 July and worked through more than 100 reports that turned out to be invalid, duplicates or not reproducible. The bottleneck is a small group of people who understand the engine well enough to choose a fix.
Embargoes get shorter and leakier. This one leaked in stages. CVE IDs circulated on 20 October with a wrong score, so PHP moved the release forward a day. Calif posted a proof-of-concept video by mistake. Then, per the PHP Foundation, Chainguard shipped fixed images more than six hours before the coordinated release. Chainguard’s CEO told The Register that his team acted on reports of active exploitation, and that they had independently rediscovered the bug starting from “a basic prompt”. AWS, meanwhile, saw an exploitation attempt in a honeypot on 17 October, before any of the public leaks.
Disclosure needs more planning, not less. OpenAI, which helped coordinate the response with CISA and other agencies, used the case to propose a five-stage framework for disclosing AI-found bugs at this scale. Whatever you think of it, the practical lesson for anyone running PHP is the same: the gap between “fix exists” and “attackers have it” is now measured in hours.
Why most public “exploits” are junk, and why you shouldn’t run them
Within hours of the release, GitHub filled up with repositories claiming to exploit PHP2Shell. The PHP security team says it inspected the proof-of-concepts that appeared after the leak and “did not identify any functional exploits at the time of release”. Elias Taylor tested the most-starred public ones and found they don’t work against a plain PHP install. Many quietly depend on a separate file-inclusion bug in the target app, and some AI-generated ones change the target server rather than prove anything.
That doesn’t make the threat fake. AWS says the bugs are now being exploited broadly, though it’s unclear how many attempts succeed. Both things are true: the repos with the most stars are mostly noise, and real attackers have something that works.
You don’t need an exploit to know whether you’re exposed. A version check answers that
There are two reasons not to “just try” one against your own server. First, a fake that fails tells you nothing, and you may conclude you’re safe when you’re not. Second, the repo itself can be the attack. A 2022 Leiden University study of GitHub proof-of-concept repositories found 899 of 47,285 that showed signs of being malicious. Running one on a laptop with your SSH keys and cloud credentials hands them over. For the same reason, I’m not linking any of them here.
What to do with your coding agent this week
This is where Claude Code, Codex or OpenCode earn their keep. The hard part of PHP2Shell isn’t the patch. It’s knowing where PHP lives: the old Dockerfile in a side project, the CI matrix still testing on 8.1, the Ansible variable nobody has looked at since 2023.
Start with AGENTS.md. Add a baseline so every future session knows it, and so the agent doesn’t helpfully reintroduce an old tag next month. Claude Code reads CLAUDE.md, which can point to AGENTS.md:
## Security baselines
- PHP in production images and CI: 8.5.12, 8.4.27, 8.3.36 or 8.2.35 or later (PHP2Shell, CVE-2026-109618 and CVE-2026-109619). Never pin 8.1 or older.
Then have it take inventory. Versions hide in more places than the Dockerfile:
Only the first row decides what serves traffic. The other two are where old versions creep back in.
I wrote a small read-only script that lists all of these. It only searches files; it doesn’t build, pull or send anything. Run it yourself, or let the agent run it as step one:
Then let it open the patch PRs. This prompt keeps the agent read-only until the last step, sorts what it finds into patched, floating, vulnerable, end-of-life and unknown, and opens one PR per repo with a deploy checklist. It also tells the agent not to fetch any exploit or “scanner” from the internet, and to treat what it reads as data rather than instructions:
If you use Codex, OpenAI has also published a PHP version checker as a Codex skill. It checks a URL’s headers or a local php -v. Its README warns that distro backports may not change the version string and that "UNKNOWN does not mean the target is patched", which is the same trap as above.
Two things the agent can’t do for you. A merged PR doesn’t patch a server: someone still has to rebuild, deploy and restart workers. And for hosts you don’t control, the answer is still a support ticket.
What this signals
PHP2Shell is a memory-safety bug in a memory-managed language. PHP developers never touch a pointer, but the engine underneath is C. Every high-level runtime has that layer, and AI-assisted research is now reading it closely and quickly.
The good news is that defenders got the same tools, and this time had about two months’ warning. The bad news is that the warning period leaked, and the next one may be shorter. The most useful thing you can do this week is boring: patch, restart, and leave behind an inventory and an AGENTS.md line so the next emergency takes an hour instead of a day.
Sources
- php.net, Security advisory: Critical remote code execution vulnerabilities, update now, 21 Oct 2026, and the PHP 8 ChangeLog
- PHP security advisories GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp
- The PHP Foundation, Today’s PHP Security Release, and How We’re Strengthening PHP Security, 21 Oct 2026
- NVD, CVE-2026-109618 and CVE-2026-109619, checked 22 Oct 2026
- Wiz Research, PHP2Shell: AI uncovers critical RCE vulnerabilities affecting 70% of the Internet, 21 Oct 2026
- OpenAI, Patch the Planet: coordinated disclosure of critical vulnerabilities, 21 Oct 2026
- CISA, Critical Vulnerabilities in PHP Require Immediate Patching, 21 Oct 2026
- AWS Security Blog, Amazon threat intelligence identifies PHP2Shell exploitation prior to public disclosure, 21 Oct 2026
- Cloudflare, Cloudflare deploys protections against php2shell vulnerability, 21 Oct 2026
- Docker, Security Update on PHP2Shell: Impact for Docker Customers, 22 Oct 2026
- Ubuntu CVE-2026-109618 and Debian security tracker, checked 22 Oct 2026
- Elias Taylor, There isn’t an easy exploit for this PHP vulnerability, 21 Oct 2026
- The Register, PHP blames supply chain security biz Chainguard for putting entire web at risk, 22 Oct 2026
- El Yadmani et al., Beyond the Surface: Investigating Malicious CVE Proof of Concept Exploits on GitHub, Leiden University
If this was useful, subscribe to Agents in Practice for one practical note on AI coding agents a week. Helping your team adopt Claude Code or Codex safely and without the surprise bill? I consult on exactly that: https://andre-burgstahler-9n5.pages.dev/.
This article was written with AI assistance and reviewed by the author.






Top comments (0)