Beyond the Hotfix
What PHP2Shell teaches us about runtime governance

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
- Find the version that's actually running. Run
php -vinside the production container or instance. composer.json, the Dockerfile, CI and production often disagree! - On 8.2 or newer: rebuild and redeploy.
- Docker:
docker build --pullso 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 -vover SSH, restart once the patched runtime reaches you, and make surelinuxFxVersion/php_versionin 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).
- Docker:
- On 8.1 or earlier: plan an upgrade now. Bump the composer.json constraint, run
composer update --lockon the new version, update the base images, then fix deprecations (8.2 deprecated dynamic properties). Most modern framework versions already support 8.3. - 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.
- Check that the fix actually landed. Run
php -vin production after the deploy. Scan your images with Trivy or Docker Scout. - 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:
# 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# 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-appFour practices that make the next fix a one-line change
- 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!
- 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.
- 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.
- 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.
# Pinned by version and digest
FROM php:8.3.36-fpm@sha256:<digest># 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.

