maborak.com~/blog/cve-2026-109619-php-worker-statesoftware & infrastructure engineering
Back to all articles

CVE-2026-109619: stale PHP state across worker requests

The producer-consumer lifetime bug behind CVE-2026-109619, conditional FPM exposure, and a practical worker-replacement and configuration review.

By the Maborak engineering team · · 6 min read

A PHP request can end while its worker process continues serving traffic. CVE-2026-109619 exploits that distinction: process-level state can retain a reference to memory whose request has already ended. Updating PHP and retiring the old worker generation are both part of remediation.

Checked 29 October 2026. This article separates PHP’s published findings from our recommended deployment review. It does not claim an independent exploit reproduction or an incident observed on a Maborak customer system.

The producer and the consumer

The advisory describes two operations: a producer leaves request-owned state reachable after its memory is released; a later consumer acts on that state before normal initialization resets it. Fatal interruption can prevent cleanup, and diagnostics during shutdown can repopulate already-cleared state. The demonstrated sequence spans separate HTTP requests handled by the same worker. PHP technical advisory.

A useful way to review this class of failure is to draw two lifetimes:

Worker process:  |-----------------------------------------|
Request A:       | allocate -> publish -> error -> release |
Worker reference:                    ---------------------->
Request B:                                                | use?

The arrow is the problem. Once request A releases its memory, the reference has no valid owner. A later operation does not need to know anything about request A to misuse it. It merely needs to trust process state that should have been invalidated.

This differs from an application leaking user data into an ordinary global variable. The security boundary here includes internal memory ownership and cleanup ordering. Reviewers should ask when each field becomes visible, which routine resets it, and whether every exit path reaches that routine. “We clear it at the next request” is only sufficient if nothing can read it earlier.

Confirmed paths and conditional exposure

PHP documents early INI diagnostics and session upload progress as consumers. PHP 8.5 fatal-error backtrace state supplies a confirmed producer. FPM terminates workers on startup failure, but a validated session path starts during application execution and is consumed by a later request. That path requires a suitable application operation. PHP technical advisory.

Red Hat likewise describes mod_php exposure and conditional FPM exposure through application-stage behavior. An nginx frontend is therefore not evidence that a PHP backend is unaffected. Red Hat CVE record.

For operational triage, map each hostname to its backend pool and executable. Record whether distinct applications share workers. A shared domain name does not necessarily mean a shared process, and different hostnames do not necessarily mean separate processes. That mapping is necessary both for patch coverage and for making sense of logs.

Fix status

PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12 are the first upstream releases fixing the two October 21 vulnerabilities. The PHP 8.5 release announcement states that updating is the safe resolution rather than relying on a configuration workaround. PHP 8.5.12 announcement.

The complete state-reset patch matters because more than one producer or consumer can exist. PHP lists disabling session upload progress and, on 8.5, fatal error backtraces as partial controls. Suppressing error output does not remove the internal diagnostic operation. PHP technical advisory.

Our deployment record should distinguish three states: update available, update installed, and updated workers serving traffic. Only the last establishes that requests have stopped reaching the old runtime. For vendor-maintained packages, attach the matching vendor advisory and package release rather than comparing upstream version numbers in isolation.

Audit the configuration path

A review should follow the configuration from its source to the process that consumes it. Search application code, generated deployment files and server configuration. The following commands are starting points; run them against the relevant checked-out configuration and code, not an unrelated home directory:

rg -n 'PHP_ADMIN_VALUE|PHP_VALUE|php_admin_value|php_admin_flag' deploy config
rg -n 'session\.upload_progress|fatal_error_backtraces' deploy config
rg -n 'ini_set|session_start|session_set_save_handler' src app

If a directory does not exist, substitute the actual deployment or source path. The output is a review queue, not a vulnerability verdict. A string in a comment is not a runtime setting, and a dynamically constructed setting may not match a literal search.

For FPM, distinguish pool configuration from values delivered by the frontend. FPM supports administrative pool values that application ini_set() calls cannot override; the manual also warns that FastCGI parameters can carry configuration and that FPM should not be exposed to arbitrary clients. FPM configuration documentation.

Record which layer owns each change. A configuration repository can say one thing while an older container image or generated pool file says another. Compare the desired configuration with a controlled observation from the serving process, then remove any temporary diagnostic route.

Apply the session mitigation early enough

The PHP notice places the upload-progress mitigation in php.ini, FPM pool or server configuration before body parsing. Runtime ini_set() and FPM .user.ini are too late for this purpose. It also requires replacing the workers. PHP security notice.

For an existing FPM pool, the relevant setting can be expressed as:

; In the existing pool configuration, before workers start.
php_admin_flag[session.upload_progress.enabled] = off

This syntax follows FPM’s administrative configuration mechanism. It is a partial mitigation for this CVE, not a substitute for the patched runtime. FPM manual.

Before rollout, identify whether the application polls PHP’s session-based upload progress. A progress indicator stopping is a different failure from the file upload failing. Test those behaviors independently: completed upload, progress feedback, cancellation, session continuity and error handling. Record the result against the pool that actually handled the request.

Replace workers and verify the replacement

Our recommended sequence for a replicated service is:

  1. Prepare the patched artifact and verify its package provenance.
  2. Test the new artifact with representative traffic in staging.
  3. Drain one backend so it stops receiving new requests.
  4. Replace its PHP workers using the deployment system’s supported process.
  5. Confirm new process start times and the effective runtime build.
  6. Run functional checks before returning the backend to service.
  7. Repeat until no old workers or old replicas remain.

For a single instance, schedule the restart according to the service’s availability requirements. Avoid claiming completion from the service manager’s success message alone. Record process inventory before and after; compare the loaded build and the backend serving a real request. Do not prescribe a generic restart command without knowing whether PHP runs as an Apache module, a separate FPM service or a container process.

Investigation needs process context

For this lifetime model, a useful investigation record includes a backend or container identifier, process identifier where available, request timestamp, application route and correlated error event. Process IDs can be reused, so pair them with host identity and a time interval. Avoid recording session contents or full request bodies merely to make correlation easier.

A burst of errors could be an application defect, resource exhaustion or probing. Treat it as a lead and correlate it with process behavior and file changes. Conversely, a clean application log does not prove the absence of an engine-level problem before application initialization.

Close the remediation task only when package evidence, worker replacement and functional verification agree. Keep the OOM corruption issue and the later session serialization issue as separate findings: one checkbox labelled “PHP2Shell” can hide an unfinished configuration review.

Back to all articles

Technologies we work with

  • Argo CD
  • Kubernetes
  • Docker
  • Podman
  • Ansible
  • Jenkins
  • Chef
  • Proxmox VE
  • Google Cloud
  • Linux
  • Red Hat
  • CentOS
  • NGINX
  • Apache
  • Traefik
  • Prometheus
  • Grafana
  • PostgreSQL
  • MySQL
  • MariaDB
  • Redis
  • etcd
  • Qdrant
  • Elasticsearch
  • Logstash
  • Kibana
  • PagerDuty
  • Go
  • Python
  • FastAPI
  • PHP
  • TypeScript
  • React