#PHP#Security#Vulnerability Management#DevOps#Docker

PHP2Shell: Triage and Patch Plan for CVE-2026-109618 and CVE-2026-109619

webhani·

On October 21, the PHP project released emergency fixes for two flaws tracked together as PHP2Shell: CVE-2026-109618 and CVE-2026-109619. According to BleepingComputer and Help Net Security, both are unauthenticated remote code execution bugs in PHP core, rated 9.2 on CVSS v4.0 by the PHP security team (Wiz describes the severity more cautiously, so ratings are not uniform across vendors). The fixed versions are 8.5.12, 8.4.27, 8.3.36 and 8.2.35.

We have not read the PHP advisory line by line ourselves, and several details below come from secondary vendor write-ups. Verify against php.net before acting. The operational lessons, though, do not depend on the fine print.

What is reported about the bugs

Based on the coverage we could find:

  • CVE-2026-109618 is described as an out-of-memory condition that triggers a longjmp(), interrupting request handling while internal request data is only partly initialized.
  • CVE-2026-109619 is described as a stale-global-state problem leading to a heap use-after-free, with memory disclosure and code execution possible. It is associated with the session.upload_progress feature.
  • Anything that serves web requests is in scope: PHP-FPM, Apache with mod_php, FrankenPHP. Reports single out mod_php as the highest risk.
  • Disclosure details reportedly leaked before the embargo ended, and the release was moved up by a day. Whether exploitation in the wild is confirmed is disputed between vendors, so plan as if it is.

Step 1: Find every PHP runtime you operate

The painful part of an event like this is rarely the patch itself. It is the inventory. PHP hides in places teams forget:

  • Base images (php:8.3-fpm, wordpress, drupal) pinned by digest months ago
  • Legacy VPS boxes running distro packages
  • Staging and preview environments
  • Client-managed servers you host or advise on

For containers, query what is actually deployed rather than what the Dockerfile says:

# Print the PHP version inside each running container that has php installed
for c in $(docker ps --format '{{.Names}}'); do
  v=$(docker exec "$c" php -r 'echo PHP_VERSION;' 2>/dev/null) && echo "$c $v"
done

For Kubernetes, the same idea with kubectl exec over a label selector works, but an image scan (Trivy, Grype) against your registry gives a broader view with less effort.

Step 2: Patch in risk order

Prioritize by exposure, not by team ownership:

  1. Internet-facing runtimes, especially mod_php on Apache
  2. Internet-facing PHP-FPM behind nginx or a CDN
  3. Internal tools reachable by many users
  4. Everything else

If you are on a supported branch, the upgrade is a patch-level bump and normally low risk:

# Before
FROM php:8.3.30-fpm-alpine
# After
FROM php:8.3.36-fpm-alpine

Rebuild with --pull so you do not reuse a cached base layer, then confirm inside the running container with php -v.

The end-of-life problem

PHP 8.1 and older no longer receive upstream updates. Reports say the security team published minimal source backports for 7.4, 8.0 and 8.1, and some distributions and LTS vendors ship their own. Bitsight's data, as quoted in the coverage, suggests only about a third of version-identifiable PHP hosts run a patched branch, with 7.4 the most common branch.

If you run an EOL branch, you have three real options: take the vendor backport, upgrade the branch (a project in its own right), or put the application behind controls that reduce exposure while you do. We would treat "we'll upgrade next quarter" as unacceptable here for anything internet-facing.

Interim mitigations: use with care

Secondary sources suggest these stopgaps. None replaces the update:

  • Set session.upload_progress.enabled=0 if you do not use it. This relates to CVE-2026-109619, and some sources recommend leaving it off after patching too.
  • For CVE-2026-109618, one source recommends an administrative memory_limit=-1 across all pools, with a warning not to substitute RLIMIT_AS. That advice is counterintuitive and we would only apply it after reading the PHP advisory, because removing memory limits has its own denial-of-service consequences.
  • Blocking multipart/form-data at the proxy for apps that never accept uploads.
; php.ini or a pool-level override
session.upload_progress.enabled = 0

Treat these as time buyers measured in hours, not a posture.

After patching

  • Restart workers. PHP-FPM and Apache keep old code in memory until reloaded.
  • Check access logs for unusual multipart requests to endpoints that do not take uploads in the days before you patched.
  • If you find suspicious activity, rotate secrets stored on that host (database credentials, API keys, .env contents).

Takeaways

  • Know your PHP inventory before the next advisory arrives. A scheduled job that records PHP_VERSION per workload pays for itself.
  • Patch internet-facing mod_php first.
  • EOL branches are a risk decision, not a backlog item.
  • Verify vendor-reported mitigation details against the official advisory before changing production configuration.