← Blog

Php2Shell Detailed Technical Analysis: CVE-2026-109618 and CVE-2026-109619

Share on X

October 21, 2026: PHP shipped fixes for two critical remote code execution flaws, CVE-2026-109618 and CVE-2026-109619, in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. PHP rates both 9.2 on CVSS v4.0. The release followed a pre-announcement on October 20 and an earlier leak of the flaws' existence. This post covers what PHP has published, what to upgrade to, how to verify the fix, and how to reduce exposure while you patch. Primary source: PHP's security advisory.

The name "PHP2Shell" is used in the press for these two flaws. Several researchers and vendors have reported on them independently, and at least one reported a 10.0 score that PHP has not adopted. We treat PHP's advisory as the authoritative source for scores, versions and classes, and mark anything else as reported.

What PHP has published

PHP's announcement describes both issues as remote code execution in the core interpreter. It names the classes below and nothing more about how they are reached:

  • CVE-2026-109618, "RCE via OOM corruption." If PHP runs out of memory at a point where request data is only partly initialised, the interrupted state can be treated as valid during request cleanup.
  • CVE-2026-109619, "RCE via stale global state." Request-owned internal state can outlive the memory that backs it. A later request handled by the same worker can use that state before normal initialisation resets it.

Both descriptions point to failures in memory lifecycle handling inside a worker process, rather than to a bug in one application's code. PHP says every installation that serves web requests is at risk, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. mod_php carries the highest risk, because it runs inside the web server's own worker processes.

Affected and fixed versions

BranchFixed inStatus 8.58.5.12Official release, 21 Oct 2026 8.48.4.27Official release, 21 Oct 2026 8.38.3.36Official release, 21 Oct 2026 8.28.2.35Official release, 21 Oct 2026. End of life 31 Dec 2026 8.1, 8.0, 7.4Backport patches (PHP-8.1-CVE-2026-109618-109619 and similar branches)No longer maintained upstream. Use a vendor backport or upgrade Older than 7.4NoneUnsupported. Upgrade

PHP has not published a single list of earliest affected versions. Other reports suggest the flaws reach back to PHP 5.4. Assume every version you run is affected until your vendor confirms otherwise.

Upgrade steps

  1. Inventory every PHP binary. Check the CLI, PHP-FPM pools, mod_php inside Apache, php-cgi, container images and any bundled runtime inside a CMS or appliance. php -v covers only the CLI.
  2. Upgrade to the fixed release for your branch. Use the official 8.x release, or a distribution package that carries the same CVE identifiers in its changelog. Linux vendors received patches before publication.
  3. Restart workers. PHP-FPM, Apache and php-cgi keep the old code in memory until restarted. Graceful reloads are enough for FPM, but confirm that every pool picked up the new binary.
  4. Rebuild container images from the patched base image, and redeploy. Patching the host alone does not patch an image that bundles its own PHP.
  5. Check CMS and plugin runtimes. WordPress, Drupal, Magento and similar stacks run on whatever PHP the server provides, so the host upgrade covers them. Any bundled or self-contained PHP build needs its own update.

Verifying the fix

  • Version: run php -v for the CLI and check the version reported by a phpinfo page or php-fpm -v for workers. Confirm it matches one of 8.5.12, 8.4.27, 8.3.36, 8.2.35, or a vendor build that lists the CVEs.
  • Loaded binary: confirm the web server reports the patched version after a restart. A worker that started before the upgrade keeps running the old code.
  • Images and artifacts: scan running containers and any golden images for the old PHP version, not only the hosts.

Reducing exposure while you patch

PHP's advisory lists mitigations that lower the risk for installations that cannot be upgraded at once. The project says they reduce exposure but do not make an installation safe, so treat them as a short bridge, not a fix.

  • Memory limits. Set memory_limit=-1 through php_admin_value in FPM or Apache config, so applications cannot override it. The advisory warns against using RLIMIT_AS or RLIMIT_DATA for this purpose.
  • Request-size limits. Set a low post_max_size (for example 8M without uploads, 32M with them), keep upload_max_filesize below it, and enforce the same limits at the reverse proxy or load balancer.
  • Upload progress. Set session.upload_progress.enabled=0 in php.ini, an FPM pool or server config, not in ini_set() or .user.ini, then restart every worker.
  • Backtraces (PHP 8.5). Set fatal_error_backtraces=0 and restart workers.
  • Diagnostics and timeouts. Remove per-request settings that emit diagnostics before initialisation, and fix any fatal errors or timeouts that an outside user can trigger.

Detection

PHP has not published indicators of compromise, and no public detection signature has been verified in the sources we reviewed. Practical steps:

  • Look for worker crashes and restarts in PHP-FPM and Apache logs, especially out-of-memory messages and segmentation faults, from the time of the release onward.
  • Alert on unusual request sizes and on repeated large POSTs to any public endpoint, because the advisory ties the memory issues to request handling.
  • Check for new or changed files under web roots, plugin directories and temporary upload paths, and for unexpected processes started by the web user.
  • Review access logs for requests that return 500 errors or time out, followed by normal traffic from the same source.

A clean log review does not prove a host was not targeted. If a patched host shows signs of unexpected activity, rebuild it from a known-good image and rotate the secrets it could read.

Timeline

  • Before October 20: the two flaws were leaked publicly, and at least one research firm reported it could reproduce one of them. Public reporting gave a CVSS 10.0 score that PHP's advisory does not use.
  • October 20: PHP published a pre-announcement with a CVSS v4.0 score of 9.2 for each flaw and scheduled the release for 14:00 UTC on October 21.
  • October 21, 14:00 UTC: PHP released 8.5.12, 8.4.27, 8.3.36 and 8.2.35, and published the advisory with CVE identifiers and mitigations.

Reports disagree about early attacks. One research firm says it saw activity against PHP sites before the release, and a national cyber agency said it had no sign of active exploitation at that point but expects large-scale attempts soon. We have not verified the early-activity claim, so treat it as unconfirmed.

Who should act first

  1. Shared hosting and control panels: you run PHP for many customers at once. Patch the shared binaries, then confirm every pool and mod_php instance restarted.
  2. Internet-facing WordPress, Drupal and custom PHP apps: patch the host and any bundled runtimes, and review logs for crashes.
  3. Container and CI builders: rebuild images from patched base images and rotate build secrets if a vulnerable image ran in production.
  4. Anyone on PHP 8.1 or older: check with your vendor for a backport now, because upstream support has ended.

Why worker reuse changes the impact

A PHP request normally starts from a clean slate: the engine allocates its request memory, initialises globals and session state, runs the script, then frees everything at shutdown. Deployment models differ in how much of the process survives between requests. PHP-FPM and mod_php keep worker processes alive and hand them many requests in turn. Anything that the engine treats as belonging to one request must therefore be reset completely before the next request starts, and a worker that was interrupted halfway through that cleanup carries its inconsistent state forward.

That is why the two issues matter more under long-lived workers than under one-process-per-request setups. It also explains why the advisory flags mod_php as the highest-risk configuration. Keep in mind that this is an explanation of why the class of bug is serious, not a description of how to trigger it. The mitigations and upgrades are the things to act on.

What each recommended setting controls

The mitigations in PHP's advisory change how much memory and input a single request can use. Knowing what each one does helps you set it correctly and check that it stuck.

  • memory_limit caps the memory a request may allocate. The advisory recommends -1, which removes the cap. Set it with php_admin_value so application code cannot raise it back, and confirm it per pool with php-fpm -tt or a per-vhost phpinfo page. Note that removing the cap changes the failure mode of runaway scripts. They will consume host memory instead of hitting a limit, so pair the change with cgroup or systemd memory limits.
  • post_max_size and upload_max_filesize bound how much request body PHP accepts. Keep upload_max_filesize below post_max_size, and enforce the same limits at the reverse proxy, because PHP only sees a request after the proxy has accepted it.
  • session.upload_progress.enabled controls the upload-progress feature. Turn it off in php.ini, the pool file or the server configuration. Setting it from ini_set() or a .user.ini file is too late for code that runs during request startup.
  • fatal_error_backtraces (PHP 8.5) controls whether fatal errors include backtraces. Turning it off reduces the detail a failing request reports to the client.

After changing any of these, restart every worker. Settings in php.ini are read at process start, so a graceful reload is the minimum, and a full restart is safer when you need certainty.

Developer checks

  • Test on a patched build in staging. Run your test suite and a load test against PHP 8.2.35, 8.3.36, 8.4.27 or 8.5.12 before rolling out. Watch for changed memory use, slower requests, and any code that depends on the removed behaviour.
  • Find code that sets the affected keys at runtime. Search the codebase, framework bootstrap files and vendor packages for ini_set calls on memory_limit, post_max_size or session.upload_progress.enabled. A call in application code overrides the server setting for that request.
  • Alert on worker lifecycle events. Track PHP-FPM child restarts, max_children reached, and out-of-memory or segmentation-fault entries in the error log. A jump in any of these after a deploy deserves investigation, whether or not it is related to this advisory.
  • Record the PHP version in your telemetry. Emit the running version as a tag on every request or deploy event, so you can answer "which services are still on a vulnerable version" from your monitoring system instead of inventorying hosts by hand.

A CI guard against vulnerable base images

Patching hosts does not fix images that bundle their own PHP. A build check can stop a vulnerable tag from shipping. This sketch fails the build when a Dockerfile pins a PHP image below the fixed release for its branch. Adapt the version map to your branches.

#!/usr/bin/env bash
# Fails if any Dockerfile pins a php base image below the fixed release for its branch.
set -euo pipefail

status=0
while IFS= read -r line; do
  tag=$(sed -E 's/^FROM +php:([0-9]+.[0-9]+.[0-9]+).*/\1/' <<<"$line")
  branch=${tag%.*}
  case "$branch" in
    8.2) fixed=8.2.35 ;; 8.3) fixed=8.3.36 ;; 8.4) fixed=8.4.27 ;; 8.5) fixed=8.5.12 ;;
    *) echo "unknown or unpatched branch: $tag"; status=1; continue ;;
  esac
  if [[ "$(printf '%s
%s
' "$fixed" "$tag" | sort -V | head -1)" != "$fixed" ]]; then
    echo "vulnerable base image: $tag (need >= $fixed)"; status=1
  fi
done < <(grep -hE '^FROM +php:[0-9]+.[0-9]+.[0-9]+' $(find . -name Dockerfile -not -path './node_modules/*'))
exit $status

Run it in CI on every pull request. It only checks explicit version tags, so also review any FROM php:8.x lines that float without a patch version, and any images built from distribution packages.

Related reading

For a WordPress plugin compromise from the same week, see Rank Math PRO. For hosting-provider exposure, see FirstVDS, and for a developer-tool release compromise, see OVHcloud CLI.

Sources

PHP security advisory, 21 Oct 2026 • PHP pre-announcement, 20 Oct 2026 • PHP 8.5.12 ChangeLog • BleepingComputer • Sansec • Tenable FAQ