PHP2Shell: Two Critical PHP Bugs You Need to Patch Today (CVE-2026-109618 & CVE-2026-109619)
Hey there! If you run anything on PHP, stop scrolling and open a terminal. Seriously. On October 21, 2026, the PHP team shipped an emergency security release for two critical bugs. Not a WordPress plugin. Not some aband
Hey there! If you run anything on PHP, stop scrolling and open a terminal. Seriously.
On October 21, 2026, the PHP team shipped an emergency security release for two critical bugs. Not a WordPress plugin. Not some abandoned Composer package. The PHP engine itself. And yes, that means a perfectly written app can still be exposed.
I'll break down what these bugs are, how they work (the 5-year-old version first, then the senior-dev one), how to check your servers, and how to patch without breaking things. No panic, no hype. Just the stuff that actually works.
1. The 30-second version
The bugs are tracked as CVE-2026-109618 and CVE-2026-109619, nicknamed PHP2Shell. Both are rated 9.2 (CVSS v4.0), and both can lead to remote code execution by an unauthenticated attacker.
| Thing | Detail |
|---|---|
| Affected | PHP 5.4 through 8.5.11 |
| Fixed in | 8.5.12, 8.4.27, 8.3.36, 8.2.35 |
| Upstream fix for 8.1 and older | No official release (source backports exist, more on that below) |
| Real fix | Update PHP, then restart everything |
| Workarounds | Partial at best. PHP itself says updating is the only safe choice |
Real talk: if you are reading this and your PHP version is below one of those numbers, you are in the "patch tonight" group.
2. The 5-year-old version
Imagine a restaurant. Every customer (request) gets a table, and a waiter sets it with plates and cutlery before the customer sits down.
Bug one (out-of-memory handling). The waiter is halfway through setting a table when the kitchen runs out of plates. Instead of finishing, he bolts out of the room. Later, the cleaner comes in, sees a half-set table, and assumes it was set properly. So he starts clearing things that were never placed. Chaos.
Bug two (stale state). When a customer leaves, the restaurant throws away their reservation slip. But the host still has a sticky note pointing at where that slip used to be. The next customer arrives, the host trusts the sticky note before checking anything, and reads whatever is sitting in that spot now.
That is basically it. One bug trusts half-built data, the other trusts a pointer to data that no longer exists.
3. The senior-dev version
Now the real names for those things.
CVE-2026-109618: RCE via out-of-memory corruption. PHP handles out-of-memory errors by exiting the current context with longjmp(). If that happens while request data is only partly initialized, PHP's request cleanup can treat the invalid data as valid. That's memory corruption an attacker can steer.
CVE-2026-109619: RCE via stale global state. PHP keeps some global state that points at memory owned by a request. After the request ends, that memory is freed, but the state survives. A later request handled by the same worker can touch that stale state before normal initialization resets it. This is a use-after-free (the advisory lists CWE-416).
Two more details that matter:
- Besides code execution, an attacker may be able to read memory from the PHP worker process. That memory can hold passwords, tokens, API keys, and certificates from other requests. Reading it does not even require code execution first.
- The bugs are in the runtime, so even a plain "Hello World" page on a vulnerable version can be attacked.
Here's the thing most people miss: updating WordPress or Laravel does not update PHP. PHP comes from your server package, your host, or your container image. Different layer, different update.
4. Why mod_php is the scary one
Not every setup is equally exposed. Every PHP that serves web requests is in scope (PHP-FPM, Apache mod_php, php-cgi, FrankenPHP, LiteSpeed), but the advisory singles out Apache mod_php as the highest risk. A demonstrated exploit there needs a single unauthenticated request, and it fires before any of your application code runs.
PHP-FPM behaves differently because it shuts the worker down when a request fails early during setup. One of the two bugs was shown to reach code execution on both mod_php and FPM, though the FPM route depends on an operation inside the running app. For the other, PHP says FPM is susceptible but no complete FPM exploit has been shown.
Translation: FPM is not "safe", it's just harder. Patch both.
5. How this blew up (the messy timeline)
This one had drama, and it's a nice case study in why embargoes are fragile.
- Oct 20: Details leaked ahead of a planned Oct 22 disclosure. PHP posted an advance notice and pulled the release forward a day.
- Oct 21, around 03:00 UTC: Cloudflare switched on default WAF rules as a stopgap.
- Oct 21, 13:34 UTC: PHP published the GitHub security advisories.
- Oct 21, 14:00 UTC: Fixed versions released.
- Later that day: watchTowr reported active exploitation attempts, and Cloudflare said attackers were changing payloads to dodge its rules.
As of the reporting I read, nobody had confirmed a successful break-in of a specific server. But some organizations took systems offline as a precaution, including government sites in the Netherlands and the HR platform BambooHR. That tells you how seriously people are taking it.
The bugs were found by researchers at Wiz Research, Calif, and OpenAI's Codex Security team, working with the PHP security team. They say AI models helped turn old, obscure flaws into working exploits much faster than a human team could. The affected code has been in PHP for more than a decade.
The PHP Foundation also published an honest post-mortem: signs of the out-of-memory problem were spotted during a 2024 audit, but no concrete route to code execution was found, competing fixes stalled, and they called the delay a structural failure of their process. Respect for saying that out loud.
6. Am I vulnerable? Check in two minutes
First, figure out which PHP actually serves your web traffic. The php on your command line can be a different install from the one behind your site.
# CLI version (may NOT be what your site uses)
php -v
# FPM binary (adjust the version number)
php-fpm8.3 -v
# Is Apache loading mod_php?
apachectl -M | grep -i php
# What PHP processes are actually running?
ps aux | grep -E "php-fpm|apache2|httpd" | head
Compare the version against the table in section 1. One catch: Linux distros and hosting vendors often backport fixes without changing the version number. So Debian or Ubuntu can show an "old-looking" version that is actually patched. Check the package changelog for the CVE instead of trusting the version string:
apt changelog php8.3-fpm | grep -E "CVE-2026-10961[89]"
If you're on shared hosting or cPanel, you can't run any of this. Ask your host which build you're on and whether it carries the fix. Some vendors have published backports for older branches, but you need to confirm for your plan.
7. Patch it (and actually restart)
On Debian or Ubuntu with a package-managed PHP:
sudo apt update
sudo apt upgrade
# then restart whatever serves PHP
sudo systemctl restart php8.3-fpm
sudo systemctl restart apache2 # or nginx, if it fronts FPM
The restart is not optional. Long-running workers keep the old code in memory until they're restarted. I know that sounds obvious, but "I patched it" and "I patched it and restarted it" are two very different sentences.
If you ship with Docker, rebuild your image from a patched base. Don't just redeploy the old one:
# Make sure the tag resolves to a patched release (8.4.27+ for 8.4)
FROM php:8.4-fpm
docker build --pull --no-cache -t myapp:patched .
docker run --rm myapp:patched php -v
Check the output says 8.4.27 or higher (or the patched equivalent for your branch). Then redeploy and confirm in production, not just on your laptop.
8. What if I really can't update yet?
Be honest with yourself here: these are band-aids. The advisory says only updating gives complete protection. But if you're waiting on a vendor, these reduce exposure to specific attack paths.
For CVE-2026-109618 (out-of-memory):
; php.ini
; Per the advisory: stop apps from overriding the limit at runtime
memory_limit = -1
post_max_size = 8M
# And cap request sizes at the web server / proxy too
client_max_body_size 8m;
Do not reach for RLIMIT_AS or RLIMIT_DATA as a substitute. PHP warns those can trigger the same vulnerable path.
For CVE-2026-109619 (stale state):
session.upload_progress.enabled = 0
; PHP 8.5 only:
fatal_error_backtraces = 0
Then restart every worker. Turning off session upload progress blocks the confirmed session paths, not every possible variant. It was circulated as a workaround before the patch and it turned out to be incomplete. Don't let it lull you into thinking you're done.
9. After you patch
Two follow-ups most people skip.
Re-check your memory settings. The fix adds a new hard memory limit. When it's reached, the process ends and shutdown handlers don't run. So review memory_limit and post_max_size against what your app really needs, or you may trade a security bug for a surprise outage.
Look for signs you were hit before patching. The researchers suggest watching for:
- unusual multipart requests followed by memory-limit errors or repeated HTTP 500s
- oddly large
PHPSESSIDcookies in responses - PHP workers restarting for no clear reason
A rough starting point on a typical Linux box (log paths vary by setup):
# Memory-limit errors in recent logs
sudo grep -R "Allowed memory size" /var/log/ 2>/dev/null | tail -n 20
# Spike of 500s in an nginx access log
awk '$9 == 500' /var/log/nginx/access.log | wc -l
If anything looks off and you handle user data, rotate secrets (API keys, DB passwords, session secrets) after patching. Memory disclosure means those could have been exposed without any visible "hack".
10. PHP 8.1 and older: the uncomfortable part
PHP 8.1 and below have reached end of life, so there is no official patched release for them. The vulnerable range goes all the way back to 5.4, so a lot of legacy sites are sitting in it.
Your options, best to worst:
- Upgrade to a supported branch (8.2 or newer). Note that 8.2 reaches end of life on December 31, 2026, so 8.3 or 8.4 is the smarter target if you can manage it.
- Use a vendor backport. The PHP security team published source backports for 7.4, 8.0, and 8.1, and some distros and hosts ship their own patched builds.
- Do nothing. Don't.
This is the "learn from it" moment for everyone with a client site running some PHP version nobody dares to touch. An old runtime is a debt that eventually gets called in.
11. It's not the only PHP bug this year
PHP2Shell is the loud one, but the patch notes this year have been busy. A few from the earlier releases, for context:
-
May 2026: a use-after-free in the SOAP extension (CVE-2026-6722) that could lead to remote code execution if you expose a vulnerable
SoapServerendpoint to untrusted users, fixed in 8.2.31, 8.3.31, 8.4.21 and 8.5.6. -
July 30, 2026: a PostgreSQL extension fix for SQL injection through a backslash breakout in
E'...'strings (CVE-2026-17543), plus BCMath and Phar fixes. - September 2026: another high-severity SOAP issue (CVE-2026-91765), along with fixes in OpenSSL certificate verification, the HTTP stream wrapper and PHP-FPM, shipped in 8.2.34, 8.3.35, 8.4.26 and 8.5.11.
If you've been running "I'll update PHP next quarter", those are your receipts for why that plan is shaky.
12. What I'm taking away from this
- Patch the runtime, not just the app. Frameworks and CMS updates don't touch the PHP underneath.
- Restart after patching. Always. Verify the running version, not the installed one.
- Know what's under your containers. Pin your base image tags, and rebuild on a schedule, not only when the news scares you.
- Run supported versions. The upgrade you keep postponing is cheaper than the incident.
- Workarounds are not fixes. Treat them as a bridge to the patch window.
That's it. That's the checklist.
Now go run php -v on every server you own. Then go restart something.
Let's Connect
I'm Prayush Adhikari, currently grinding through computer engineering and building software on the side. I write about things I run into while building, breaking, and (sometimes) fixing stuff.
If this saved you a late night, drop a comment and tell me what you're running (mod_php, FPM, Docker, shared hosting?) and whether you've patched yet. And if you've got questions, ask. I'll answer what I can.
- LinkedIn: https://linkedin.com/in/adhikareeprayush
- GitHub: https://github.com/adhikareeprayush
- Portfolio: https://prayushadhikari.com.np
Which would you rather read next: a hands-on guide to hardening PHP-FPM, or a breakdown of how use-after-free bugs actually work?
References
- PHP 8.5.12 and 8.4.27 release notes: https://github.com/php/php-src/releases
- GHSA-w8hw-w9fx-j79w (CVE-2026-109618): https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w
- GHSA-6wmf-4rv5-p3rp (CVE-2026-109619): https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp
- The Hacker News coverage: https://thehackernews.com/2026/10/php-issues-emergency-patches-for-two.html
- Google Cloud guidance: https://cloud.google.com/blog/products/identity-security/responding-to-core-php-vulnerabilities-cve-2026-109618-cve-2026-109619
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.