Skip to content

PHP2Shell: two critical PHP flaws, and what they mean for your Microsoft 365 tenant

Published 23 October 2026

On 21 October 2026 the PHP project released fixes for two critical vulnerabilities, both rated CVSS 9.2:

CVE What goes wrong
CVE-2026-109618 Memory corruption when a request hits the memory limit, leading to remote code execution
CVE-2026-109619 Leftover state from an earlier request is reused by the next one, leading to remote code execution

Details leaked a day before the release, proof-of-concept exploits are public, and researchers report exploitation attempts against internet-facing servers. CERT-EU considers exploitation likely. Treat this as urgent.

Any PHP installation that serves web requests: PHP-FPM, Apache mod_php (highest risk, according to the PHP team), php-cgi, FrankenPHP and LiteSpeed. The attack works before any application code runs, so a well-written app does not protect you.

PHP branch Fixed in
8.5 8.5.12
8.4 8.4.27
8.3 8.3.36
8.2 8.2.35
8.1 and older No official release. Upgrade, use a vendor backport, or build from the PHP team’s source patches (7.4, 8.0, 8.1)

PHP is often inside products that don’t advertise it: CMS platforms such as WordPress, intranet portals, help desks, monitoring tools and appliances. The Dutch NCSC keeps a list of products known to embed PHP (see Sources).

  1. Update PHP to a fixed version on every server, starting with internet-facing ones. Linux distributions received the patches in advance; install your vendor’s updated package.
  2. Azure App Service on Linux: Microsoft has rolled out the fixed built-in PHP images. The Latest channel gets fixes first, Standard soon after, and Extended last. For internet-facing apps, move to Latest or Standard (Configuration → Stack settings → Platform Release Channel). Confirm with php --version in the app’s SSH console.
  3. Azure App Service on Windows: the built-in PHP runtimes are end-of-life and won’t be patched. Move the app to Linux, or bring your own supported PHP runtime.
  4. Containers and custom runtimes: rebuild your images with a fixed PHP version. Updating the host doesn’t patch PHP inside a container.
  5. Can’t patch today? Put a web application firewall in front and reduce exposure. Microsoft is adding a managed rule to Azure Front Door WAF (rollout expected to finish by 28 October 2026) and has published an interim rule for Application Gateway. CERT-EU also lists PHP settings that lower the risk, such as turning off session.upload_progress.enabled and lowering post_max_size. These measures help, but only the update fixes the flaws.

PHP2Shell is not a Microsoft 365 vulnerability. Entra ID and Exchange Online are not affected. The risk is indirect, and it’s the part that is easy to miss.

Many PHP apps connect to your tenant: a website that sends mail through Microsoft Graph, a portal with “Sign in with Microsoft”, or a tool that reads users from Entra ID. These apps usually keep an Entra app client secret or certificate in a config file on the server. Once an attacker controls the server, they can read that secret and use the app’s permissions from anywhere, with no MFA or Conditional Access prompt in their way.

If you ran an affected PHP app that connects to Microsoft 365:

  1. Find the app registrations it uses. Search the server’s config for the app (client) ID, then open it in Entra admin center → App registrations.
  2. Rotate its credentials. Create a new client secret or certificate, deploy it to the patched server, then delete the old one. Do the same for any other passwords or API keys stored on the server.
  3. Review what it did. In Entra admin center → Sign-in logs → Service principal sign-ins, look for that app signing in from unexpected IP addresses since mid-October. Check the audit logs for changes it made.
  4. Trim its permissions. An app that only sends mail doesn’t need Mail.ReadWrite for every mailbox or Directory.ReadWrite.All. Remove what it doesn’t use, and limit mail access to specific mailboxes where possible.

Find PHP on your devices with Microsoft Defender. If your servers are onboarded to Microsoft Defender for Endpoint, run this query in Advanced hunting. It was checked by Griffin31’s security experts and lists every device with any sign of PHP in the last 30 days: installed software, running processes, PHP loaded inside a web server, and PHP files on disk. Compare the versions it finds with the fixed versions above.

// PHP in use: any device with ANY sign of PHP, last 30 days
let lookback = 30d;
let PhpExe = @"(?i)^php[\w.\-]*(\.exe)?$"; // php, php8.2, php-fpm8.3, php-cgi.exe, phpdbg
let PhpLib = @"(?i)^(libphp[\w.\-]*\.so|php\d*(ts)?\.dll|php\d*apache[\w.\-]*\.dll)$"; // PHP inside Apache/IIS
let Installed = DeviceTvmSoftwareInventory
| where SoftwareName has "php"
| project DeviceName, Signal = "Installed (inventory)", Detail = strcat(SoftwareName, " ", SoftwareVersion), Timestamp = datetime(null);
let Running = DeviceProcessEvents
| where Timestamp > ago(lookback)
| where FileName matches regex PhpExe or InitiatingProcessFileName matches regex PhpExe
| project DeviceName, Signal = "Running process", Detail = coalesce(FolderPath, FileName), Timestamp;
let Loaded = DeviceImageLoadEvents
| where Timestamp > ago(lookback)
| where FileName matches regex PhpLib
| project DeviceName, Signal = "Loaded in web server", Detail = strcat(InitiatingProcessFileName, " loads ", FileName), Timestamp;
let OnDisk = DeviceFileEvents
| where Timestamp > ago(lookback)
| where FileName =~ "php.ini" or FileName matches regex PhpExe or FileName matches regex PhpLib
| project DeviceName, Signal = "PHP files on disk", Detail = FolderPath, Timestamp;
union Installed, Running, Loaded, OnDisk
| summarize Signals = make_set(Signal), Details = make_set(Detail, 10), LastSeen = max(Timestamp) by DeviceName
| extend SignalCount = array_length(Signals)
| sort by SignalCount desc, LastSeen desc

Griffin31 checks your Microsoft 365 configuration, not your web servers, so it won’t report a PHP version. It covers the identity side of this incident. These recommendations are the ones to check:

  1. Review unfamiliar or unneeded App Registrations: find the apps your PHP servers sign in with, and remove the ones nobody uses.
  2. Application secrets approaching expiration: shows which apps hold a client secret, the credential an attacker can read from a breached server.
  3. Application certificate maximum lifetime (180 days): short-lived certificates limit how long a stolen credential keeps working.
  4. Email notifications for vulnerabilities: Microsoft Defender emails you when it finds a critical flaw like this one on your devices.