A critical flaw in a shared runtime can put unrelated applications on the same incident-response clock. The difficult question is which deployed services expose the vulnerable code—and who can update them before attackers reach them.

PHP has released fixes for CVE-2026-109618 and CVE-2026-109619, also discussed as PHP2Shell. The operational priority is now deployment and verification of those fixes.

Updated October 21, 2026, 14:04 UTC (17:04 EEST). This revision replaces our 08:23 UTC pre-release assessment with the published PHP advisories. The original release schedule was 14:00 UTC, or 17:00 in Finland. Earlier statements that fixes and vendor technical details were pending describe the morning only.

TL;DR

  • Fixed releases are 8.2.35, 8.3.36, 8.4.27 and 8.5.12.
  • Both vulnerabilities are rated CVSS v4.0 9.2 and can permit unauthenticated remote code execution.
  • Apache mod_php has demonstrated exploitation; FPM is also affected, with different prerequisites.
  • Disabling upload progress is not a complete fix. Deploy the corrected runtime and verify every serving worker.
  • Demonstrated exploitation in research must not be presented as evidence of attacks in the wild.

Confirmed Scope and Fixed Versions

PHP’s October 21 security announcement warns about PHP installations serving web requests, including FPM, mod_php, CGI, FrankenPHP and LiteSpeed. This is a broad remediation scope, not proof that every deployment is exploitable through the same request.

PHP branchFirst upstream release fixing both CVEs
PHP 8.28.2.35
PHP 8.38.3.36
PHP 8.48.4.27
PHP 8.58.5.12

The versions listed above are fixed, not vulnerable. Within each branch, earlier releases require an update unless the package vendor confirms backported fixes for both CVEs. Use the listed release or a later corrected release in that branch.

PHP 8.1 and older are outside normal upstream support. PHP also supplied minimal source backports for 7.4, 8.0 and 8.1; these do not restore support. Check distribution or LTS vendor fixes, or migrate. Do not interpret omission from the table as safety, or repeat the early “every version since PHP 5” claim as an exact verified matrix. Vendor backports may retain older version numbers.

Technical Analysis: Two Distinct Failure Modes

CVE-2026-109618: corruption during out-of-memory handling

PHP can abandon work when memory runs out while request data is only partly initialized. Cleanup can then use that invalid state. The official OOM advisory confirms unauthenticated RCE against mod_php, before application code runs, with normal input and memory limits.

FPM terminates a child when startup fails, blocking that particular sequence. Application-time memory exhaustion can still expose vulnerable cleanup; the advisory identifies FPM susceptibility through source analysis but does not demonstrate a complete exploit for this CVE against FPM. FrankenPHP susceptibility is inferred from its shutdown behavior; LSAPI exploitation is described as likely but unvalidated.

For temporary exposure reduction, PHP discusses administratively enforcing memory_limit=-1. This removes the predictable PHP limit failure, not underlying allocation failures. Removing the limit also requires availability planning: bound decoded request sizes and resource use outside PHP. Container or cgroup limits are not a complete mitigation; do not substitute RLIMIT_AS or RLIMIT_DATA, which can trigger the vulnerable allocation failure. A patched release is the complete remedy.

CVE-2026-109619: stale state across requests

A worker can retain pointers to memory freed after a request. A later request reaching the same worker can use that stale state before initialization resets it. The official state-lifecycle advisory confirms session-lifecycle RCE against mod_php and FPM; FPM requires a suitable application operation after successful startup. PHP 8.5 fatal-error backtraces provide another confirmed mod_php case.

Upload progress is therefore one path, not an explanation or workaround covering both CVEs. For temporary reduction:

  • Disable session.upload_progress.enabled in configuration effective before request parsing, then restart workers. This covers the confirmed session paths only.
  • On PHP 8.5, disabling fatal_error_backtraces blocks the confirmed backtrace path only.
  • Remove invalid or deprecated early per-request configuration and address attacker-reachable fatal errors. Hiding diagnostics does not prevent the underlying access.

Other state and extension paths remain possible. Multiple workers reduce the probability of requests reaching the same worker but do not remove the vulnerability. The complete state-reset patch is required.

What Changed Since the Morning Assessment

The morning article correctly labeled its version scope and upload-progress explanation as provisional. This revision replaces those provisional claims with the vendor’s two distinct mechanisms and published fixes. The earlier caution about treating upload-progress disabling as a universal remedy remains valid.

Our reviewed vendor advisories establish technical exploitation, but do not establish an observed criminal campaign. We therefore make no current claim that exploitation in the wild is either confirmed or absent. The morning’s bounded third-party observations should not be carried forward as fresh monitoring evidence.

Why Runtime Exposure Matters

Different applications can share a PHP runtime, while one hosting account can contain several versions. Updating application code alone does not repair the interpreter beneath it.

For each service, connect the public request path to its actual handler, package build, effective configuration and worker privileges. Use the confirmed attack prerequisites to prioritize response, not to postpone patching while attempting to prove exploitability.

A static site without a PHP request handler lacks this direct execution path. Separate APIs and other connected services still need their own assessment. Website market-share figures cannot provide a reliable count of exploitable installations.

What You Can Do Today

1. Check Your Exposure on Linux

These read-only checks assess CVE-2026-109618 and CVE-2026-109619, not every possible website vulnerability or evidence of a past compromise. Run them through SSH on the server that actually executes PHP. They do not send exploit requests, install packages or restart services. Use only the commands applicable to your environment.

Find the runtime serving your domain. Start with the operating system and running processes:

Terminal window
cat /etc/os-release
ps -eo pid,ppid,lstart,args | grep -E '[p]hp-fpm|[p]hp-cgi|[a]pache2|[h]ttpd|[f]rankenphp|[l]sphp'

This lists candidate processes and start times, not a complete inventory. No match is not proof of safety: containers, remote backends, permissions and on-demand workers can hide the relevant runtime.

For Apache, use its configuration wrapper to inspect configured modules:

Terminal window
apachectl -M

On Debian/Ubuntu the wrapper may be named apache2ctl. A PHP module indicates mod_php is configured; proxy_fcgi_module alone does not prove a particular domain uses FPM. A permission or configuration error means this check is incomplete, not that PHP is absent. These results describe the configuration on disk; running processes may still use an older configuration.

Inspect your domain’s enabled virtual-host configuration locally. Follow NGINX fastcgi_pass, or Apache SetHandler/ProxyPassMatch, to the matching FPM socket, pool or remote backend. Common configuration roots are /etc/nginx/, /etc/apache2/ and /etc/httpd/. With mod_php, identify the PHP library in LoadModule. Do not publish configuration dumps or create a public phpinfo() page.

Identify the installed build. The following is a useful starting point, but reports the CLI binary only:

Terminal window
php -v

For FPM, check the binary belonging to the service you identified—for example /usr/sbin/php-fpm8.3 -v or /usr/bin/php-fpm -v. Paths and version suffixes vary. This reports the binary currently on disk, not necessarily what an older worker has loaded.

Run the package query for your distribution:

Terminal window
# Debian / Ubuntu: look for installed rows marked "ii"
dpkg-query -l 'php*' 'libapache2-mod-php*'
# Arch / CachyOS: list installed PHP packages
pacman -Q | grep -E '^php'

Match the handler’s binary or module to its owning package. For example, after replacing the path with the one you actually found:

Terminal window
# Debian / Ubuntu example
dpkg-query -S /usr/sbin/php-fpm8.3
# Arch / CachyOS example
pacman -Qo /usr/bin/php-fpm

Custom builds and hosting-panel packages may not appear in these queries. Treat them as unverified until their supplier confirms the build and fixes. Repeat the checks inside each relevant container or on each remote PHP backend; host packages do not establish a container’s patch status.

Compare against authoritative fixes. Use the branch-specific table above for upstream releases. For distribution packages, match your OS release, package source and full package version against the vendor’s status for both CVEs. For example, Ubuntu publishes separate records for CVE-2026-109618 and CVE-2026-109619. A lower upstream number can contain a backported fix; a third-party repository does not automatically inherit the distribution’s fix status.

Record the result for each domain/backend:

ResultEvidence and next action
Correction verified for these CVEsThe serving runtime maps to a corrected build, and all relevant workers were replaced after deployment. Keep that evidence.
Update requiredThe serving build is affected and has no verified backported fix. Patch promptly or assess containment.
Not yet verifiedThe handler, package provenance, backport status or running-worker state is unclear. Resolve that gap; do not mark the site safe.
No direct PHP path identifiedThe domain is confirmed static with no PHP backend. Assess separate APIs and services independently.

Use deployment records and process start times together to confirm worker replacement; installing a package alone is insufficient. Without SSH access, ask your hosting provider to confirm the domain’s handler, full corrected package version, coverage of both CVEs and worker replacement time. Disabled upload progress does not change an unpatched build into a corrected one.

2. Deploy fixes or contain exposure

Use your vendor’s corrected package or a supported fixed upstream release. Ask hosting providers for evidence covering your actual runtime and account. Upstream publication alone does not prove that a downstream package has been deployed.

For services that cannot be patched promptly, assess temporary removal from public access against business impact and data sensitivity. Record any workaround’s limited coverage and expiration. Test form and upload behavior after request restrictions; a configuration change that breaks legitimate uploads still does not establish complete protection.

3. Investigate behavior without inventing CVE-specific indicators

Investigate unexpected child processes of php-fpm, php-cgi, httpd or apache2. Correlate process ancestry with request timing, outbound connections and file changes, using normal application behavior as the baseline.

Crashes and HTTP 5xx responses have many causes; HTTP 200 is not proof of successful exploitation. Missing shell activity cannot exclude malicious code running inside a worker. Treat these as investigation leads, not CVE-specific signatures.

If compromise is suspected, preserve logs and host evidence, contain the service, and investigate persistence and exposed credentials. Patching does not remove an existing foothold.

4. Verify deployment across every instance

Record the advisory and corrected package build, replace or restart workers as required, and confirm every replica uses the corrected runtime. Exercise login, session, form and upload flows. Use vendor backport evidence rather than the upstream version string alone.

Sources