BoostPHP2Shell exposure check

Security advisory · updated 23 October 2026

PHP2Shell: unauthenticated remote code execution in the PHP engine

CVE-2026-109618 and CVE-2026-109619, both rated Critical (CVSS 4.0 base 9.2). Disclosed and patched on 21 October 2026.

Upgrade to PHP 8.2.35, PHP 8.3.36, PHP 8.4.27, PHP 8.5.12, PHP 8.6.0RC4 or later and restart every PHP worker. PHP 8.1 and older receive no upstream release. Configuration changes reduce risk but, in the PHP project's words, there are no complete mitigations.

Check your domains

Summary

PHP2Shell is the name given to a set of memory-safety bugs in the core PHP engine that let an unauthenticated attacker run code on a PHP server over plain HTTP. They are tracked by the PHP project as two advisories:

CVEGitHub advisoryPHP project titleSeverity
CVE-2026-109618GHSA-w8hw-w9fx-j79wRCE via OOM corruptionCritical 9.2
CVE-2026-109619GHSA-6wmf-4rv5-p3rpRCE via stale global stateCritical 9.2

CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N. Network-reachable, no privileges or user interaction, full confidentiality, integrity and availability impact. Rated high complexity because each target needs heap-layout tuning.

What makes PHP2Shell unusual is where the bugs live. They are not in WordPress, Drupal, Laravel or any other application. They are in how PHP itself recovers from fatal errors while handling a request. The application does not need to contain a bug. Researchers report that a minimal "Hello World" script on an affected version is enough, and that nearly every PHP release back to 5.4 is affected by at least one of the issues.

Affected and fixed versions

BranchFixed inStatus
PHP 8.28.2.35Security fixes only; end of life 31 December 2026, so plan an upgrade
PHP 8.38.3.36Supported
PHP 8.48.4.27Supported
PHP 8.58.5.12Supported
PHP 8.68.6.0RC4Pre-release; RC4 and later include the fix
PHP 8.1 and older (incl. 7.x, 5.x)No upstream releaseEnd of life. See options for end-of-life versions

All SAPIs that serve web requests through long-lived workers are in scope: PHP-FPM, Apache mod_php, and similar. The bugs depend on state surviving from one request to the next in the same worker process.

A follow-up issue, CVE-2026-115560 (session upload progress when the serialize handler is switched from php_binary/php_serialize to php at runtime), was announced on 23 October 2026 and will be fixed in the next PHP release. This scanner will be updated when fixed versions are published.

Technical details

Root cause: unsafe recovery from fatal errors

When PHP hits a fatal error mid-request, most notably running out of memory, it historically used longjmp() to abandon the request immediately. That jump can happen at a moment when engine data structures are half-built: a pointer has been published to a global but the memory behind it is not yet initialised, or has already been freed.

Two consequences follow:

With a groomed heap, either of these becomes a use-after-free or type confusion that the attacker controls.

The individual bugs

Wiz Research described four distinct bugs reachable this way. The PHP project groups them under the two CVEs above.

  1. Session upload-progress unserializer use-after-free. An allocation failure while decoding session upload-progress data leaves the unserializer's global state published. A later request on the same worker reuses it after the attacker has reclaimed that memory.
  2. Remote process-memory disclosure through PHPSESSID. An out-of-memory error during early multipart (RFC 1867) handling leaves a session-ID pointer dangling. A subsequent multipart request can receive reclaimed heap contents back in its PHPSESSID response cookie. This works even if the application never calls session_start(), and gives an attacker the memory-layout information needed to make the other bugs reliable.
  3. Fatal-error backtrace use-after-free. After an out-of-memory fatal error, EG(last_fatal_error_backtrace) can retain a pointer to freed memory that an early diagnostic in the next request dereferences. The PHP project confirmed this RCE path on PHP 8.5's fatal_error_backtraces feature.
  4. OPcache type confusion. An allocation failure in zend_accel_script_persist() can leave OPcache's shared-memory slot metadata out of sync, so another worker sees a pointer of the wrong type.

The researchers expect further variants of the same pattern. The fix therefore targets the pattern, not just these four bugs:

Exploitation and impact

Detection

What this scanner checks

It sends one ordinary GET / to each domain and reads:

Versions are compared to the table above. It cannot see versions that are hidden (expose_php = Off), behind a CDN, or patched by a distribution backport, so confirm on the server:

# CLI and FPM can differ; check the one serving web traffic
php -v
php-fpm8.3 -v          # Debian/Ubuntu naming; RHEL: php-fpm -v
# or, temporarily, a protected page containing: <?php echo PHP_VERSION;

Indicators of attack

Look for these in web, PHP-FPM and container logs:

If you find the memory-disclosure indicator or post-exploitation signs, treat the host as compromised: patch, rotate secrets that the PHP process could read, and investigate.

Remediation

Upgrading is the only complete fix. After upgrading, restart every PHP worker (PHP-FPM pools, Apache, application containers). Workers that are still running keep vulnerable state in memory.

Official Docker php images

# Dockerfile: pin a fixed release (8.2.35 / 8.3.36 / 8.4.27 / 8.5.12; any variant: -fpm, -apache, -cli, -alpine)
FROM php:8.3.36-fpm
# Rebuild pulling fresh base layers, then confirm
docker build --pull -t myapp .
docker run --rm myapp php -v

Floating tags such as php:8.3-fpm pick up the fix only when you rebuild with --pull. Redeploy every service built on them.

Debian and Ubuntu

Distributions often backport fixes and keep the old upstream version number (e.g. 8.2.7-1~deb12u1), so a version that looks old may be patched. Check your release's tracker, then upgrade:

sudo apt update
apt list --upgradable 2>/dev/null | grep -i php
sudo apt upgrade
sudo systemctl restart php8.2-fpm apache2   # adjust to your PHP version / web server

RHEL, AlmaLinux, Rocky, Fedora

sudo dnf upgrade 'php*'
sudo systemctl restart php-fpm httpd

Check Red Hat CVE-2026-109618 and CVE-2026-109619 for errata. RHEL builds keep the upstream version string without a suffix, so this scanner can't recognise a backport. Confirm with your errata status. Remi repository users: update from Remi.

Alpine

apk update && apk upgrade --available
php -v    # Alpine packages are named per branch, e.g. php83, php84

Windows, macOS and source builds

Managed hosting, cPanel and Plesk

Apply the panel's PHP updates (cPanel EasyApache ea-php* packages, Plesk PHP handlers) and confirm every PHP version offered to sites is updated, not only the default. On shared or managed hosting, ask your provider to confirm they have deployed the fixed versions and restarted workers.

End-of-life versions (PHP 8.1 and older)

The PHP project will not release fixes for 8.1 or older. In order of preference:

  1. Upgrade to a supported branch (8.3 or newer recommended; 8.2 ends on 31 December 2026).
  2. Use an LTS vendor or distribution that backports security fixes, and confirm their package includes these CVEs.
  3. Build from source with the minimal backports the PHP security team published for 7.4, 8.0 and 8.1 (see the php.net release announcement).

Running end-of-life PHP also leaves earlier unpatched vulnerabilities in place. Treat it as urgent regardless of PHP2Shell.

Temporary mitigations (not a fix)

The PHP project is explicit: these do not make an installation safe. Updating is the only safe choice. Use them only to reduce risk until you can patch.

Settings must apply before request parsing: put them in php.ini, an FPM pool (php_admin_value) or the web-server config, not ini_set() or .user.ini. Then restart every worker.

; php.ini or FPM pool (php_admin_value[...] = ...)
memory_limit = -1                      ; CVE-2026-109618: primary config mitigation (partial)
post_max_size = 8M                     ; 32M if uploads are required
session.upload_progress.enabled = 0    ; CVE-2026-109619: if you don't need upload progress
fatal_error_backtraces = 0             ; PHP 8.5 only: removes the confirmed CVE-2026-109619 RCE path

Timeline

19 Aug 2026First vulnerability discovered
20 Aug 2026Unauthenticated RCE confirmed against Drupal
21 Aug 2026Unauthenticated RCE confirmed against WordPress
24 Aug 2026Reported to the PHP security team
21 Sep 2026PHP acknowledges and begins a coordinated fix
21 Oct 2026PHP 8.2.35, 8.3.36, 8.4.27, 8.5.12 and 8.6.0 RC4 released; public disclosure
23 Oct 2026Follow-up CVE-2026-115560 announced, fix due in the next release

References

This advisory summarises the public sources above in our own words. Where they differ, the PHP project's advisories take precedence.