PHP2Shell is the name for two critical PHP bugs, CVE-2026-109618 and CVE-2026-109619, that allow unauthenticated remote code execution. PHP fixed them on October 21, 2026. CISA added both to its Known Exploited Vulnerabilities (KEV) catalog on October 26 with a due date of October 29. That deadline has passed. If you still have unpatched PHP serving web traffic, treat it as a live incident, not a backlog item.

This morning I wrote about taking RDP and SSH off the internet with Azure Bastion. This afternoon is about the other front door: the web tier. Here's how to find every PHP runtime in your Azure estate, patch it, and check whether someone got in first.

TL;DR

  • What: two PHP flaws (both CVSS v4.0 9.2, per PHP) that let an unauthenticated request run code. PHP says the risk is highest for Apache with mod_php, where a demonstrated exploit fires before any application code runs.

  • Who: every PHP installation serving web requests, including PHP-FPM, mod_php, php-cgi, FrankenPHP and LiteSpeed.

  • Fix: PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35 (or your distro's fixed package), then restart PHP-FPM or the web server.

  • Azure: App Service on Linux built-in runtimes are patched, but not on the Extended release channel first, not in custom containers, and not on Windows, where the built-in PHP runtimes are end of life.

  • Also patch the kernel: CISA says a Linux kernel bug, CVE-2026-46300, can be chained with PHP2Shell to implant webshells and run commands as root.

What is PHP2Shell?

From PHP's October 21 security advisory:

  • CVE-2026-109618 (RCE via OOM corruption): out-of-memory handling can interrupt PHP while internal request data is only partly initialized, and request cleanup may then treat that invalid data as valid.

  • CVE-2026-109619 (RCE via stale global state): request-owned internal state can survive after its memory is freed, and a later request on the same worker may use it before normal initialization resets it.

Microsoft's MSRC says exploitation attempts were reported before the coordinated disclosure date and several proof-of-concept exploits appeared within hours of the fixes. CISA's alert puts it plainly: organizations that can't update, or that still run PHP 8.1 or earlier unsupported versions, should take those systems offline until they're patched.

Who patches what in Azure?

Where PHP runs

Who fixes it

What you do

App Service on Linux, built-in PHP 8.2 to 8.5

Microsoft (rolled out to Latest and Standard channels on Oct 21)

Move off the Extended channel, verify the version, upgrade any EOL runtime

App Service on Windows, built-in PHP

Nobody. Microsoft says these runtimes are EOL and no patch is planned

Move to App Service on Linux, or bring your own supported PHP runtime

Custom containers / bring-your-own PHP

You

Rebuild images on a fixed PHP and redeploy

Linux VMs and scale sets

Automatic guest patching or OS image upgrades, inside your maintenance window (Linux distros like Azure Linux and Ubuntu)

Don't wait for a distant window on internet-facing hosts; patch now with Azure Update Manager

PHP you installed on Windows (IIS)

You. Windows Update can't patch it

Install a fixed php.net build, recycle app pools or FastCGI processes

Step 1: Find your App Service PHP apps

Example, adapt before use. This lists every web app in the current subscription with its Linux stack string, so you can spot PHP apps and their versions:

az webapp list --query "[].{name:name, rg:resourceGroup}" -o tsv |
while read -r name rg; do
  az webapp config show -n "$name" -g "$rg" \
    --query "{app:name, stack:linuxFxVersion, phpWindows:phpVersion}" -o tsv
done | grep -i php

Anything on PHP 8.1 or older is end of life and won't get the fix, even if you change the release channel. For the rest, in the portal open the app, go to Stack settings, set Platform Release Channel to Latest or Standard, and save. The App Service team recommends Latest for internet-facing or high-risk apps because it gets fixes first.

Verify it worked: open an SSH session to the app (the App Service team points to the Web SSH page on your app's .scm.azurewebsites.net site) and run php --version. You want 8.2.35, 8.3.36, 8.4.27 or 8.5.12 or later.

WordPress note: Microsoft says apps from the official WordPress on App Service Marketplace offering were updated, except those still on the older Alpine-based images, which won't be patched.

Step 2: Patch PHP and the kernel on Linux VMs

Example commands, adapt to your distro and PHP packaging:

# What's installed?
php -v
dpkg -l | grep -E '^ii\s+php'      # Debian/Ubuntu
rpm -qa | grep -i php                # RHEL/Azure Linux

# Update, then restart so the fixed runtime actually loads
sudo apt-get update && sudo apt-get install --only-upgrade 'php*'
sudo systemctl restart php*-fpm apache2   # use the unit names on your box

# Kernel fix for the CVE-2026-46300 chain needs a reboot
uname -r
sudo reboot

On a fleet, use Azure Update Manager for a one-time update on internet-facing machines rather than waiting for the next scheduled window, which is what MSRC recommends when the window is days away. Defender Vulnerability Management and Defender for Cloud software inventory can help you find PHP you didn't know you had. CISA points out that PHP is often embedded in other software, so it won't always show up as a package named "php".

Step 3: If you can't patch today

PHP's own interim measures reduce exposure but don't make an install safe:

  • Set session.upload_progress.enabled=0 in php.ini or the FPM pool (not via ini_set() or .user.ini) and restart every worker. This blocks the confirmed session paths for CVE-2026-109619.

  • On PHP 8.5, set fatal_error_backtraces=0 and restart workers.

  • For CVE-2026-109618, PHP suggests memory_limit=-1 enforced with php_admin_value, a low post_max_size (8M without uploads, 32M with), and a container or cgroup memory limit. Don't use RLIMIT_AS or RLIMIT_DATA, which can trigger the vulnerable path.

  • Put the app behind Azure WAF. Microsoft has published PHP2Shell upgrade guidance and Azure WAF mitigations. A WAF is a speed bump, not a patch.

Step 4: Check for compromise

Because exploitation started early, patching isn't the end. CISA marks both PHP CVEs and the kernel CVE for forensic triage in the KEV catalog, and its alert says to watch for PHP worker processes launching shells or downloading tools. A quick first pass (example, adapt before use):

# Shells or downloaders spawned under PHP workers
ps -eo pid,ppid,user,etime,cmd --forest | grep -B2 -A3 -E 'php-fpm|apache2|httpd' | grep -E 'sh -c|bash|curl|wget'

# PHP files changed since disclosure (Oct 20, 2026) in your web root
sudo find /var/www -name '*.php' -newermt '2026-10-20' -ls

CISA has also published a SIGMA detection rule for this activity in its SIGMA rules GitHub repository. If you find a webshell, don't just delete it. Isolate the host, preserve evidence, rotate every secret the app could read (connection strings, storage keys, API tokens), and rebuild from a clean image. Managed identities and Key Vault references make that rotation much less painful.

Common pitfalls

  • Patching without restarting. Running PHP-FPM workers keep the old code until restarted.

  • Forgetting containers. Your base image froze PHP at build time. Rebuild and redeploy.

  • Assuming Windows App Service is covered. It isn't. Built-in PHP there is EOL.

  • Stopping at PHP. Patch and reboot for CVE-2026-46300 too, so a web foothold can't become root.

  • PHP on Windows and Brotli. PHP shipped rebuilt Windows packages (8.5.12-1, 8.4.27-1, 8.3.36-1, 8.2.35-1) with Brotli 1.2.1 for CVE-2026-111497, also in KEV. The version number doesn't change, so check the build suffix.

Key takeaways

  • PHP2Shell is exploited and the KEV deadline has passed. Patch internet-facing PHP first, today.

  • App Service on Linux is patched on Latest and Standard. Extended, custom containers, EOL versions and Windows are your problem.

  • Restart workers, rebuild images, and reboot for the kernel fix.

  • Hunt for webshells and rotate secrets on anything that was exposed before you patched.

Related reading: the same "exploited, patch now" pattern hit self-managed GitLab and Ivanti Connect Secure in the last week.

Sources

Patched everything already, or found a PHP runtime hiding somewhere you didn't expect? Tell me in the comments. I read every one.