PHP2Shell is the name for two critical vulnerabilities in the PHP runtime itself, CVE-2026-109618 and CVE-2026-109619, patched on 21 October 2026. Both can give an attacker remote code execution on a web server without logging in, and on Apache with mod_php a single request can trigger the attack before your application code even runs. The fix is to update to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35 (or your vendor's patched package), then restart every PHP worker. If you can't do that today, there are interim settings that reduce the risk, but the PHP project is clear that updating is the only complete fix.
I'm Kunal Vohra. I have an M.Tech in Cybersecurity from NIT Kurukshetra and I've been the technical co-founder of six startups, so I've been on the receiving end of more than one "patch everything by tonight" morning. This is the guide I'd hand a founder or a small engineering team: what happened in plain language, then the exact steps, in order.
What is PHP2Shell?
PHP2Shell is two memory-safety bugs in how PHP sets up and tears down web requests. Neither lives in WordPress, Laravel or your code; they are in the PHP engine, so every framework running on an affected version inherits them.
CVE-2026-109618: remote code execution through out-of-memory corruption. If PHP hits its memory limit at the wrong moment while setting up a request, some internal request data is left only partly initialised. The cleanup code then treats that broken data as valid, which corrupts memory. On Apache with mod_php, researchers demonstrated code execution with default settings from an unauthenticated request. On PHP-FPM it was confirmed through certain application code paths.
CVE-2026-109619: remote code execution through stale global state. A fatal error at the wrong point can leave internal state pointing at memory that has already been freed. The next request handled by the same worker can then use that leftover state, a classic use-after-free. Code execution was demonstrated against a real application on Apache with mod_php.
The PHP project rates both critical, CVSS v4.0 9.2. (A leaked CVE listing showed 10.0; that was wrong.) The researchers at Calif reported the issues through coordinated disclosure.
How the PHP2Shell disclosure unfolded
The timeline matters because attackers had a head start, so "we'll patch in the next maintenance window" is not good enough here.
- Before 20 October: Calif reports the bugs to the PHP security team. Linux distributions and long-term-support vendors receive patches in advance.
- 17 October: Amazon Threat Intelligence records a PHP2Shell exploitation attempt on its MadPot honeypot, four days before public disclosure. How the attacker got the details is not known.
- 20 October: Details leak on social media ahead of the planned 22 October disclosure. The PHP team announces an emergency release for the next day.
- 21 October, 14:00 UTC: PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 ship with the advisories. watchTowr reports seeing exploitation in its honeypot network from the same day.
If there is one line to remember from this incident: a single unauthenticated request, before any of your code runs, was enough to take over an Apache mod_php server. No plugin choice or code review protects you from that. Only the runtime version does.
Who is affected by CVE-2026-109618 and CVE-2026-109619?
Effectively every PHP installation that serves web requests and hasn't been patched since 21 October. Google's advisory puts the affected range at PHP 5.4 through 8.5.11.
Affected server setups: PHP-FPM, Apache with mod_php (highest risk), php-cgi, FrankenPHP and LiteSpeed.
Fixed versions by branch:
- PHP 8.5: fixed in 8.5.12
- PHP 8.4: fixed in 8.4.27
- PHP 8.3: fixed in 8.3.36
- PHP 8.2: fixed in 8.2.35 (note that 8.2 reaches end of life on 31 December 2026)
- PHP 7.4, 8.0 and 8.1: no official release. The PHP team published minimal source backports, and some distributions and LTS vendors ship patched packages. Otherwise, upgrade.
- PHP 7.3 and older, including PHP 5: no fix at all. Upgrade to a supported branch.
That covers most WordPress sites, most Laravel and Symfony apps, many internal admin tools, and a surprising number of appliances. Palo Alto Networks, for example, said all PAN-OS and Panorama versions are affected. If your startup's main product is in Node, Python or Go, you are probably still running PHP somewhere: the marketing site, a help centre, an old billing tool, a phpMyAdmin someone set up in year one. My own site runs on Next.js, so the site itself was never exposed, but that's exactly the kind of assumption the first step below exists to test.
How to fix PHP2Shell, step by step
Work through these in order. Steps 1 to 4 are the fix; step 5 is for anything you can't patch today; steps 6 and 7 are what most teams skip.
Step 1: Find every PHP installation you run
Make a list before you patch anything, starting with whatever is reachable from the internet. Include servers, containers, base images, staging environments, and anything a vendor hosts for you.
On each Linux server, these show what is installed and what is running:
# Which PHP the command line uses
php -v
# Installed PHP packages (Debian/Ubuntu)
dpkg -l | grep -i php
# Installed PHP packages (RHEL, Rocky, Alma, Fedora)
rpm -qa | grep -i php
# PHP processes actually running right now
ps -eo pid,lstart,cmd | grep -E "php|httpd|apache2" | grep -v grep
Be careful with php -v: it reports the command-line PHP, which can be a different build from the one serving web traffic. A server can have several PHP versions side by side. Check the FPM binary (for example php-fpm8.3 -v) or the Apache module, and check every container image separately:
docker run --rm --entrypoint php your-image:tag -v
Step 2: Check whether each one is already patched
Compare each version to the fixed list above. The catch: distributions often backport fixes without changing the upstream version number, so an Ubuntu or Red Hat package can say 8.1 or 8.3.x and still be patched. For distribution packages, compare the full package version against your vendor's security notice (Ubuntu's is USN-8948-1) rather than the PHP version string.
On managed hosting, ask your host directly whether the 21 October release is applied to your server. On WordPress you can see the PHP version under Tools, then Site Health, then Info, then Server, but the same backport caveat applies.
Step 3: Patch PHP
Pick the path that matches each install.
Ubuntu and Debian servers:
sudo apt update
sudo apt install --only-upgrade 'php*'
RHEL, Rocky, Alma and Fedora:
sudo dnf upgrade 'php*'
If you install PHP from the volunteer-run rpms.remirepo.net repository, the PHP team advised switching to your distribution's packages or building from source, because that repository had no update on release day.
Docker and Kubernetes: a running container never updates itself. Rebuild every image on a patched base and redeploy:
docker build --pull --no-cache -t your-image:patched .
Then roll the new image out to every service and pod. On Google Cloud, App Engine standard on PHP 8.2+ and Cloud Run services with automatic base-image updates are patched for you; everything else needs a rebuild and redeploy.
Building from source: download the fixed release from php.net, or apply the minimal backport branch for 7.4, 8.0 or 8.1.
Managed WordPress and shared hosting: most hosts patched at server level or put a firewall rule in front while they rolled out the fix. Your job is to confirm it in writing, take a backup, and, if the host forces an upgrade from PHP 8.1 or older, test the site (especially checkout and forms) on a staging copy. Don't edit server settings yourself on shared hosting.
PHP 8.1 or older with no vendor patch: this is the moment to upgrade to 8.2 or newer. Test themes, plugins and libraries on staging first; old code is exactly where an upgrade breaks.
Step 4: Restart every PHP worker and confirm the new build is running
This is the step people miss. Updating the package does nothing for workers that are already running; they keep the vulnerable code in memory until they restart.
# PHP-FPM (use your version's service name)
sudo systemctl restart php8.3-fpm
# Apache with mod_php
sudo systemctl restart apache2 # or: httpd
Then run the ps -eo pid,lstart,cmd command from step 1 again and make sure no PHP or Apache process started before the patch. Finally, confirm the web-facing runtime, not just the CLI, reports the fixed version or patched package. If you use a temporary phpinfo() page to check, delete it immediately afterwards.
Step 5: If you can't patch today, reduce the risk
The PHP project published interim settings. They lower the risk; they do not make an unpatched server safe. Apply them in php.ini, the FPM pool file or the Apache config (not with ini_set() or .user.ini, which apply too late), then restart every worker.
For CVE-2026-109619 (stale global state):
; Disable session upload progress
session.upload_progress.enabled = 0
; PHP 8.5 only: disable fatal error backtraces
fatal_error_backtraces = 0
For CVE-2026-109618 (out-of-memory corruption):
; In the PHP-FPM pool, so applications cannot override it
php_admin_value[memory_limit] = -1
; Keep request bodies small. If you don't need uploads:
post_max_size = 8M
; If you do need uploads:
; post_max_size = 32M
; upload_max_filesize = 24M
Removing the memory limit is a deliberate trade: it takes away the out-of-memory trigger but lets one bad request use more memory, so put a container or cgroup memory limit around PHP as the safety net. The PHP team specifically warns against using RLIMIT_AS or RLIMIT_DATA for this, because they can trigger the vulnerable failure.
Also:
- Enforce request size, field count, header count and multipart limits at your web server or proxy, including for requests without a
Content-Lengthheader. Block multipart requests entirely if the app doesn't take uploads. - Remove invalid or deprecated per-request PHP settings (in
.htaccess, Apachephp_valuelines, orPHP_VALUEpassed from a front end). Hiding the warnings doesn't help. - On PHP-FPM,
pm.max_requests = 1recycles a worker after every request, which limits stale state, at a real performance cost. - If a system can't be patched or mitigated, take it off the public internet until it can. The UK's NCSC advised exactly that.
Step 6: Add a firewall rule in front, as a second layer
A web application firewall buys time while you patch; it doesn't replace patching. Cloudflare deployed rules for the known exploit patterns to all customers, including free plans; on paid plans, check its managed rules are set to block, not just log. On Google Cloud, Cloud Armor's managed rules cover it; Google recommends enabling at least the File Upload and RFI categories and blocking request bodies too large to inspect. If you're on AWS, Azure or another WAF, check your provider's PHP2Shell advisory.
Step 7: Check whether you were already hit
Exploitation started before the patch, so a server that was exposed between 17 October and the moment you patched should be checked, not assumed clean. None of the advisories I read publish specific indicators of compromise yet, so this is a general post-RCE check rather than a PHP2Shell signature:
- New or changed files in the web root, especially
.phpfiles in upload folders, cache folders or anywhere PHP shouldn't be:
sudo find /var/www -name "*.php" -newermt "2026-10-17" -ls
- Unexpected processes or outbound connections from the web server user (
www-data,apache,nginx). - New cron jobs, SSH keys or system users, and on WordPress, new administrator accounts or plugins you didn't install.
- Web server logs with unusually large or malformed requests, especially multipart uploads to endpoints that don't take uploads, around worker crashes.
- Rotate secrets the server could read (database passwords, API keys, cloud credentials in environment files) if anything above looks wrong. Code execution means anything the PHP process could read should be treated as exposed.
If you find something, isolate the server, keep the logs, and rebuild from a known-good image rather than cleaning in place. Scanners can help with discovery: Searchlight Cyber released an open-source php2shell-scanner, and the major vulnerability scanners added checks.
After the patch: undo the temporary settings
Once every runtime is patched and restarted, restore a finite memory_limit, revert pm.max_requests and any upload limits you tightened beyond what the app needs, and test under load. Then rescan to confirm nothing was missed.
What PHP2Shell should change in how a startup runs security
The patch is the easy part. The hard part, every time, is step 1: nobody had a list. Three habits make the next one of these a two-hour job instead of a two-day one.
Keep an inventory of runtimes, not just services. For every system, write down the language runtime, version, where it's hosted and who owns it. The forgotten marketing site and the internal tool from year one are always the ones that get hit.
Never run an end-of-life runtime on the internet. PHP 8.1 and older got no official fix. Anything past end of life means "the next critical bug has no patch," so build the upgrade into the roadmap before the deadline, not during an incident. PHP 8.2 joins that list on 31 December.
Make patch-and-restart boring. Automatic base-image rebuilds, a deploy pipeline that can roll every service in an hour, and a written order of operations. This sits in the first section of my startup security checklist, and it's one of the first things investors probe in technical due diligence.
If you don't have someone who owns this, it doesn't need to be a full-time CTO at $180,000 to $260,000 a year. A technical advisor retainer ($750 a month for 15+ hours, held through December 2026) covers a review of your inventory, patch process and exposure. If you need someone to own security, architecture and the team, that's a fractional CTO engagement ($2,500 a month for 50+ hours on the same terms); the fractional CTO cost guide shows market rates beside mine.
Frequently asked questions
What is PHP2Shell? PHP2Shell is the name for two critical PHP runtime vulnerabilities, CVE-2026-109618 and CVE-2026-109619, disclosed and patched on 21 October 2026. Both can allow unauthenticated remote code execution on servers running PHP, rated CVSS v4.0 9.2.
Which PHP versions fix CVE-2026-109618 and CVE-2026-109619? PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. PHP 7.4, 8.0 and 8.1 have minimal source backports and some vendor packages; PHP 7.3 and older have no fix. Distribution packages may be patched under an older version number, so check your vendor's advisory.
Is my WordPress site vulnerable to PHP2Shell? If it runs on an unpatched PHP version, yes; the bugs are in PHP itself, not in WordPress or plugins. Most managed and shared hosts have patched or put firewall protection in place, but confirm with your host in writing that the 21 October release is applied to your server.
Is updating PHP enough, or do I need to restart? You need to restart. Running PHP-FPM workers and Apache processes keep the old code in memory until they restart, so restart every PHP service after updating and confirm no process predates the patch.
Can I mitigate PHP2Shell without updating? Partly. Disabling session upload progress, removing the memory limit with a cgroup limit as a backstop, tightening request size limits, and putting a WAF in front all reduce risk. The PHP project says none of these make an unpatched installation safe; take unpatchable systems off the internet.
Is PHP2Shell being exploited? Yes. Amazon recorded an exploitation attempt on 17 October, before disclosure, and watchTowr reported exploitation in its honeypots from 21 October. Treat any server that was exposed in that window as worth checking for compromise.
If you're not sure where PHP is running in your company, or whether what you found is clean, book a 30-minute call. Bring your list of servers and hosts, and I'll help you work out what to patch first and what to check. Or get in touch if you'd rather write first.
Sources
- PHP security release announcement, 21 October 2026 (php.net)
- Today's PHP Security Release (The PHP Foundation)
- PHP2Shell FAQ (watchTowr)
- PHP2Shell: find, mitigate and patch (Qualys)
- Responding to core PHP vulnerabilities (Google Cloud)
- PHP2Shell patched, update now (Help Net Security)
- What WordPress site owners need to do (Codeable)
Written By
Kunal Vohra
Technical Co-Founder & Fractional CTO
I've co-founded 6+ startups across India, the UAE, and the US, spanning AI, Web3, fintech, and cybersecurity. I write about the technical and strategic decisions that determine whether a startup thrives or stalls.
Comments
Loading comments…