PHP · Cybersecurity · DevOps

PHP2Shell: where the PHP flaws are and how to patch

A detailed response guide to the two critical PHP runtime flaws, with source-backed mechanisms, fixed versions and an operational patch checklist.

TOPIC HUBE-commerce Engineering
Close-up photograph of code in a browser developer inspector.
Photo: Markus Spiske / Unsplash. Licensed illustrative photograph of code on a screen.

PHP2Shell is the name used for two critical PHP runtime vulnerabilities, CVE-2026-109618 and CVE-2026-109619. They involve memory exhaustion and request state that outlives its memory. The security releases arrived on 21 October 2026. If you operate PHP websites, patch the runtime and replace the running workers; updating a CMS or Composer dependencies alone does not complete that job.

This guide explains the affected boundary, the difference between the two bugs, and a practical response for application owners and infrastructure teams. Sources were checked on 23 October 2026. The mechanisms and release information below come from the linked primary advisories; the deployment gates and evidence checklist are engineering recommendations.

Where exactly is the problem?

The vulnerable boundary is inside PHP's native request lifecycle: allocation, request startup, error handling and cleanup. A web server passes a request to PHP; PHP prepares internal input and extension state; application code then runs; PHP cleans up the request while a persistent worker may remain available for another request.

The PHP Foundation explains that the bugs sit in central memory-management and error-handling machinery. Apache mod_php has a demonstrated path that executes before application code. This makes a login check in a framework controller an unreliable boundary against that path. The native runtime has already processed input before the controller can reject it.

Think of three different lifetimes: the incoming request, memory allocated for that request, and the server worker. Request memory should end with its request. The second vulnerability breaks that relationship by allowing the longer-lived worker to retain a reference to the shorter-lived memory.

CVE-2026-109618: an unsafe exit during memory exhaustion

The OOM advisory describes an abrupt longjmp() exit when an allocation fails. Internal request data can still be incomplete at that moment. Cleanup subsequently treats that invalid state as usable. An ordinary memory-limit error can therefore become memory corruption rather than a clean failed request.

The release replaces that unsafe OOM exit with a deferred soft limit at a VM safe point and a higher hard limit that immediately terminates the process. This is an engine repair, not an input-validation rule.

CVE-2026-109619: state survives after its memory is freed

The stale-state advisory describes request-owned state retained by a worker after the request heap is released. An interruption can miss a reset. A later request on the same worker consumes the dangling state before normal initialization replaces it: a use-after-free.

The PHP 8.5 fatal-backtrace and session upload-progress paths are confirmed examples. Reachability differs by SAPI, configuration and application behavior. Multiple workers may complicate an attack; they do not establish that the unsafe lifecycle is absent.

Original engineering diagram: unsafe request cleanup and stale worker state sit inside PHP, before application checks in demonstrated paths. The licensed cover photograph illustrates code inspection.
Original engineering diagram: unsafe request cleanup and stale worker state sit inside PHP, before application checks in demonstrated paths. The licensed cover photograph illustrates code inspection. Open for a larger view

Which internal state is involved?

Wiz's original research identifies concrete examples: session ID state PS(id), unserializer bookkeeping BG(unserialize), and the fatal-backtrace global EG(last_fatal_error_backtrace). These are PHP internals, not names of vulnerable application database fields.

The researchers demonstrated both remote code execution and separate process-memory disclosure. Their WordPress, Drupal and Joomla demonstrations establish practical impact in tested deployments; they do not mean every deployment has an identical exploit chain. Treat a reachable unpatched runtime as urgent without claiming that every exposed website has already been compromised.

Affected release lines and fixed versions

The PHP release announcement gives these upstream security releases:

Release lineVulnerable upstream releases in that lineFixed release
PHP 8.2Earlier than 8.2.358.2.35
PHP 8.3Earlier than 8.3.368.3.36
PHP 8.4Earlier than 8.4.278.4.27
PHP 8.5Earlier than 8.5.128.5.12

Older branches require special care. They are outside normal upstream support, but some vendors supply security backports; PHP also published minimal source backports for 7.4, 8.0 and 8.1. A source patch is not proof that your installed package or container includes it. Obtain an explicit vendor statement covering both CVEs or move to a supported, fixed runtime.

CERT-EU's advisory rates both vulnerabilities critical, CVSS v4.0 9.2, and includes PHP-FPM, mod_php, CGI, FrankenPHP and LiteSpeed in the exposure assessment. The urgency extends beyond a particular CMS.

A low-looking version number can still contain a fix

Distribution packages can retain an older upstream base while backporting the repair. For example, Ubuntu USN-8948-1 lists 8.3.6-0ubuntu0.24.04.13 for Ubuntu 24.04 and 8.1.2-1ubuntu2.28 for Ubuntu 22.04 among its corrected packages.

Compare the complete package revision with the notice for your exact distribution release and repository. Neither “8.3.6 is lower than 8.3.36” nor “the package manager says latest” is sufficient evidence by itself. The repository must actually provide the relevant security fix.

Inventory the runtime that serves traffic

Start with read-only inspection. The PHP CLI options document version, configuration and extension inspection:

command -v php
php -v
php --ini
php -m
php -r 'printf("PHP=%s SAPI=%s\n", PHP_VERSION, PHP_SAPI);'

These commands describe that CLI binary. A machine can have a patched CLI and an older FPM service, Apache module or container image. Record each domain's actual upstream, FPM socket or module, package source, runtime version, image digest and instance identity.

For an Ubuntu 24.04 deployment using PHP 8.3, package inspection could include:

dpkg-query -W 'php8.3*' 'libapache2-mod-php8.3'
apt-cache policy php8.3-fpm libapache2-mod-php8.3

Adapt package names to the installed stack. Check the web SAPI through an existing private diagnostic or authenticated operations channel reached through the real serving path. Return only version, SAPI and instance identity. Do not publish a public phpinfo() page or a secret-bearing configuration dump.

Patch and prove the whole fleet changed

Use this rollout sequence as an operational plan:

  1. Map exposure. Include alternate hostnames, preview installations, old virtual hosts, direct origin access and replicas outside the main load balancer.
  2. Select a trusted fixed build. Match both CVEs to an upstream release or the applicable vendor package notice. Keep runtime and extensions compatible.
  3. Prepare recovery. Back up application data and configuration. Keep a known-good patched artifact available; a rollback that restores the vulnerable runtime is an exposure decision.
  4. Exercise a canary. Test login, sessions, legitimate uploads, imports, checkout, APIs and scheduled jobs. Check error rate, latency, memory and extension compatibility.
  5. Replace running processes. Updating files on disk does not demonstrate that existing workers loaded the new engine. Drain and restart or replace every affected worker and replica.
  6. Verify coverage. Gather the serving runtime and artifact identity from every instance, including instances that autoscaling may create later. Then inspect the remaining traffic and failure signals.

For an installation that really uses the Ubuntu php8.3-fpm service, a configuration check followed by a planned restart might be:

sudo /usr/sbin/php-fpm8.3 -t
sudo systemctl restart php8.3-fpm
sudo systemctl is-active php8.3-fpm

An active service only proves it is running. Check its package revision and the web response from each instance as well. Apache mod_php requires replacement of the Apache processes carrying the module. Restarting Nginx alone does not replace a separate FPM runtime.

For containers, rebuild from a fixed base, publish a new immutable image, roll it out, and confirm no old image digests remain in serving replicas or deployment templates. Editing a running container creates a repair that can disappear at the next deployment.

Why the patch changes OOM monitoring

The updated PHP memory-limit documentation describes a soft limit and a separate memory_hard_limit_percent boundary. A hard-limit termination skips shutdown callbacks and can report exit status 137, which also appears with external SIGKILL scenarios. Use stderr and platform events to distinguish the cause.

Engineering implication: do not interpret every post-update worker replacement as an intrusion, and do not rely on a shutdown callback as the only place to persist important business state. Durable work should have a recoverable state transition before a worker can vanish. Measure this behavior in staging without sending exploit requests to production.

If an immediate update is blocked

CERT-EU recommends updating and isolating affected services when that cannot happen promptly. Temporary settings reduce particular paths; they do not provide a general fix.

Examples include disabling session upload progress before request parsing and restarting all workers, and, for PHP 8.5, disabling fatal-error backtraces. Configuration location matters: a change inside an application script can arrive after the vulnerable startup work. The FPM configuration manual explains administrative pool settings and how php_admin_value prevents application overrides. The session documentation also places upload-progress handling before scripts run.

PHP discusses administratively enforced memory_limit=-1 as a partial OOM mitigation. Do not copy it blindly: it removes PHP's normal memory ceiling, leaves underlying allocation-failure paths, and needs a carefully designed external availability boundary. It is a short-lived incident measure under the official guidance, not a substitute for a fixed build.

Prefer a clearly owned containment decision: restrict access, disable unneeded upload paths at the frontend, or temporarily isolate the affected service while the runtime is repaired. Document business impact and the expiry of each temporary change.

Cloudflare, WAFs and managed cloud services

Cloudflare reports default protections for free and paid WAF customers beginning on 21 October at 03:02 UTC, along with observed attack traffic. This is the provider's account of its edge protections. Check that traffic actually traverses the protected hostname and that alternate origins are not exposed. A WAF is an additional boundary, not evidence that the origin runtime was updated.

Google Cloud's response distinguishes automatic updates for supported App Engine standard runtimes from customer redeployment responsibilities on other paths, including container-based services. “Hosted in the cloud” does not identify who owns the PHP patch. Obtain service-specific evidence rather than assuming that a VM, CDN or managed database updates your application image.

Was exploitation observed before disclosure?

Yes, attempts were observed. Amazon Threat Intelligence reported a MadPot attempt dated 17 October, four days before public disclosure, followed by broader attempts. Its report also says it was unclear whether those attempts would have succeeded against real systems. Preserve that distinction between a detected attempt and a confirmed compromise.

For your own environment, retain relevant evidence from at least 17 October where available. Correlate web requests, worker failures, process execution, file changes and outbound connections by time and instance. Investigate unexpected secrets exposure as well as code execution. An empty application log does not prove that native request processing was safe.

If credible compromise evidence appears, involve incident response, preserve evidence, rebuild from trusted artifacts and rotate affected credentials through a controlled process. Applying a patch prevents the repaired bug from being reused; it does not remove an existing foothold.

Completion criteria

Close the patch task when every serving runtime has a documented fix for both CVEs, all old workers and images are replaced, normal business flows pass, and investigation findings have a separate owner. Record the vendor notice, full package revision or image digest, restart time, per-instance verification and remaining exceptions.

Related engineering guides: drain Kubernetes traffic before workers exit, roll out NetworkPolicy restrictions safely, and bound overload and retries. More operational guidance is available in the engineering article library.

Primary references

Official references

These references document the tools discussed. Examples and design decisions are illustrative and should be adapted to the project and its versions.

Prepared by: Noor Yasser

FROM DECISION TO DELIVERY

Working through a similar engineering challenge?

I help teams turn architecture decisions into a clear scope and dependable, reviewable implementation.

Book a 30-minute callRelated serviceBackend engineering & API integrationsRelevant projectLogistics at scale