Skip to content
DashboardContact us

Today

Beyond the Hotfix

What PHP2Shell teaches us about runtime governance

A laptop showing code, with a blue PHP elephant plush toy on its keyboard
Published Date
Share this post

Two critical flaws in the core PHP runtime, nicknamed PHP2Shell, allow unauthenticated remote code execution and memory disclosure. They're rated CVSS 9.2. Details leaked before the planned disclosure, patches landed on 21 October, and exploitation is reportedly already happening.

Here's what's affected, a checklist for auditing your PHP projects, and four practices that turn the next critical PHP fix into a one-line change.

What the two flaws do

  • CVE-2026-109618: an out-of-memory condition interrupts a request part-way through, and request cleanup then treats the half-initialised data as valid.
  • CVE-2026-109619: request state survives after its memory has been freed, and the next request handled by the same worker can use it.

Who's affected

  • Affected: PHP 5.4 to 8.5.11.
  • Fixed in: 8.5.12, 8.4.27, 8.3.36 and 8.2.35.
  • No fix for 8.1 or earlier. They're end-of-life, so the only fix is to upgrade.

A checklist for auditing your PHP projects

  1. Find the version that's actually running. Run php -v inside the production container or instance. composer.json, the Dockerfile, CI and production often disagree!
  2. On 8.2 or newer: rebuild and redeploy.
    • Docker: docker build --pull so you don't reuse a cached base image.
    • AWS Elastic Beanstalk: apply the new platform version now instead of waiting for the managed update window. Also update any platform version pinned in your IaC (CDK, Terraform).
    • Azure App Service (built-in PHP): Microsoft rolls out patch releases on its own schedule. Check php -v over SSH, restart once the patched runtime reaches you, and make sure linuxFxVersion / php_version in your IaC is on 8.2 or newer.
    • Buildpacks: a redeploy picks up the latest patch release that matches your constraint (e.g. ~8.3.0).
  3. On 8.1 or earlier: plan an upgrade now. Bump the composer.json constraint, run composer update --lock on the new version, update the base images, then fix deprecations (8.2 deprecated dynamic properties). Most modern framework versions already support 8.3.
  4. Add a WAF as a stopgap while you patch. Turn on managed rule sets (Cloudflare, AWS WAF, Azure Front Door), and add rate limits and request-body size caps, since one of the bugs is triggered by running PHP out of memory. A WAF reduces the risk but doesn't fix it.
  5. Check that the fix actually landed. Run php -v in production after the deploy. Scan your images with Trivy or Docker Scout.
  6. Make sure you hear about the next one first. Subscribe to the php-announce mailing list, track end-of-life dates (endoflife.date), and schedule weekly container image scans in CI. Dependabot won't flag the PHP runtime because it isn't a Composer package.

The commands, in one place:

bash
# 1. What's actually running in production
php -v

# 2. Rebuild without reusing a cached base image
docker build --pull -t my-app .

# 3. On 8.1 or earlier, after bumping the composer.json constraint
composer update --lock

# 5. Check the patched image
trivy image my-app

Four practices that make the next fix a one-line change

  1. Pin exact versions. Pin your container's base image to an exact PHP release (for PHP2Shell, 8.3.36 or equivalent), by version and digest. You know exactly what's running!
  2. Scan on every change. Build the image on every pull request and run it through a scanner such as Trivy from Aqua Security. It checks every OS package and PHP dependency against public vulnerability databases, and can fail the build on a fixable critical finding, before anything is deployed.
  3. Know your blind spots. Scanners read package databases. PHP in the official Docker images is compiled from source, so a scanner can miss a flaw in PHP itself. Pinning and watching advisories still matter alongside scanning.
  4. Rebuild. On buildpack platforms, the PHP version you run is whatever was current at your last deploy. If you haven't deployed since the 21st, you probably haven't got the fix.
bash
# Pinned by version and digest
FROM php:8.3.36-fpm@sha256:<digest>

Background

PHP2Shell (CVE-2026-109618 and CVE-2026-109619) is a pair of critical flaws in PHP itself. A week earlier, Drupal shipped its own critical remote-code-execution fix (SA-CORE-2026-014, fixed in 10.6.19, 11.3.19 and 11.4.10), so if you run Drupal, check both.

End-of-life runtimes are a vulnerability that's just waiting for a CVE. PHP 8.1 stopped receiving security fixes in December 2025. If you're still on it, this is your sign.

If you run PHP, check your version today: 8.5.12, 8.4.27, 8.3.36 and 8.2.35 are the patched releases.

Official advisory: php.net security announcement, 20 October 2026

Update, 27 October 2026

The PHP team has released rebuilt Windows packages (8.2.35-1, 8.3.36-1, 8.4.27-1 and 8.5.12-1) that bundle Brotli 1.2.1, fixing CVE-2026-111497, an out-of-bounds write in Brotli decompression. PHP's cURL extension can reach the affected code when automatic HTTP response decompression is enabled. It's off by default, but some applications and HTTP client libraries turn it on.

If you run PHP on Windows, install the -1 build even if you're already on a patched version. The PHP version is the same, so php -v won't show the difference; check the build you installed instead. Linux and container builds aren't affected by this one.

Release announcement · Windows downloads