On October 21, 2026, PHP disclosed two Critical unauthenticated RCE flaws and Node.js published a High-severity fix for an out-of-bounds write in its bundled Brotli decoder. The Node.js advisory says the flaw permits RCE; actual exposure depends on whether untrusted Brotli data reaches the decoder.
Both bugs live below application dependencies. Updating WordPress, Composer packages, or package-lock.json does not patch the runtime. Replace the PHP or Node.js binary, restart every long-lived process, and verify production executes the fixed version.
On this page
- The short answer
- Why the PHP vulnerabilities are unusual
- CVE-2026-109618: an out-of-memory escape corrupts request state
- CVE-2026-109619: stale global state crosses request boundaries
- Temporary PHP mitigations are not a substitute for patching
- The Node.js issue: an out-of-bounds write in the bundled Brotli decoder
- The Node.js release fixes more than Brotli
- A safe production upgrade checklist
- 1. Inventory the executable that is actually running
- 2. Back up for rollback, then update through a supported channel
- 3. Restart every persistent process
- 4. Verify compatibility and health
- 5. Preserve evidence without mistaking errors for compromise
- Patch the runtime, then prove the worker changed
- Official references
The short answer#
Patch these versions now:
| Runtime line | First fixed release |
|---|---|
| PHP 8.2 | 8.2.35 |
| PHP 8.3 | 8.3.36 |
| PHP 8.4 | 8.4.27 |
| PHP 8.5 | 8.5.12 |
| Node.js 22 | 22.23.4 |
| Node.js 24 | 24.22.1 |
| Node.js 26 | 26.12.1 |
Node.js 18 and 20 are outside upstream support. Move those deployments to a supported line. For any PHP or Node.js package maintained by an operating-system vendor, verify its advisory and package revision because vendors may backport a fix without adopting the upstream version number.
After installing an update, restart PHP-FPM, Apache mod_php, Node.js services, process managers, and containers. A patched file on disk does not protect a worker that still has the old executable mapped into memory.
Why the PHP vulnerabilities are unusual#
CVE-2026-109618 and CVE-2026-109619 are not ordinary application bugs. They affect PHP’s request lifecycle and memory state. Both are rated 9.2 Critical under CVSS 4.0 by the PHP project.
CVE-2026-109618: an out-of-memory escape corrupts request state#
PHP historically used longjmp() to escape from an out-of-memory condition. If an allocation fails while request memory is reachable but not fully initialized, PHP can jump out without leaving state that shutdown code can safely process.
Multipart parsing can reach this condition through excessive per-part headers, empty file controls that still create metadata, deeply nested field names, or a body that evades the initial apparent size check.
Apache mod_php is the clearest exposure. Apache invokes PHP request shutdown after startup fails, so invalid state can be consumed before application code runs. PHP validated unauthenticated HTTP RCE under normal prefork configurations and default input and memory limits.
PHP-FPM exits a child when request startup fails, blocking that exact sequence. An attacker-reachable application path can still run out of memory after startup and leave invalid state for shutdown. The advisory considers FPM susceptible but does not claim a complete FPM exploit for this CVE alone.
The patch replaces the unsafe OOM escape with a delayed soft OOM at a safe VM point and a hard exit at a higher threshold.
CVE-2026-109619: stale global state crosses request boundaries#
Persistent PHP workers reuse a process for many requests. CVE-2026-109619 covers cases where a fatal error, timeout, OOM, or late diagnostic leaves global error, session, object, or extension state pointing into a freed request heap.
Exploitation needs two operations:
- A producer request publishes state and exits before that state is safely reset.
- A consumer request reaches the same worker and uses the stale pointer before normal initialization replaces it.
Multiple workers make that sequence less deterministic but do not remove it. PHP validated RCE against mod_php and PHP-FPM through session upload progress, which is enabled by default and runs before ordinary session initialization. No session_start() call is required, although the demonstrated FPM path needs a suitable attacker-reachable application operation.
This is also why secure file handling is broader than checking an extension. The controls in our PHP upload security guide remain important, but only a runtime update fixes these lifecycle flaws.
Temporary PHP mitigations are not a substitute for patching#
If an emergency update is impossible, PHP documents temporary risk reductions:
- For CVE-2026-109618, set
memory_limit=-1administratively and restart every worker. An underlying allocation failure can still reach the vulnerable path. - Disable
session.upload_progress.enabledand restart every worker to block the demonstrated session producer and consumer. - On PHP 8.5, disable
fatal_error_backtracesto remove the producer used by one confirmed path. - For PHP-FPM generally, consider
pm.max_requests=1as a costly way to prevent each child from carrying state across multiple requests. - Bound decoded request size, multipart parts and headers, input nesting, and uploads at the frontend.
No generic configuration covers every application, extension, or server path. Installing a fixed release is the only reliable mitigation.
The Node.js issue: an out-of-bounds write in the bundled Brotli decoder#
CVE-2026-111497 affects Node.js 22, 24, and 26. Node.js classifies it as High severity and states that the out-of-bounds write permits remote code execution.
Brotli is bundled with Node.js, so npm audit may not identify it. Exposure exists when an application, framework, proxy, crawler, or dependency asks Node.js to decode attacker-controlled Brotli data. Direct use of zlib.createBrotliDecompress() is an obvious path, but indirect decompression matters too.
The Node.js release notes identify the correction as a Brotli dependency cherry-pick. They do not publish the exploit mechanics, so do not treat an assumed malformed-stream shape as a deployment precondition.
RCE is the worst-case impact, not proof that every Node.js server is exploitable. A service that never decodes untrusted Brotli has a smaller reachable surface, but bundled native code can be reached through dependencies that are not obvious from JavaScript imports.
The Node.js release fixes more than Brotli#
The October 21 security releases also address several independent flaws:
| CVE | Severity | Affected lines | Practical concern |
|---|---|---|---|
| CVE-2026-105482 | High | 22, 24, 26 | dns.resolve() truncates names containing a NUL character |
| CVE-2026-105483 | High | 24, 26 | TLS hostname bypass with IP addresses written using fullwidth digits |
| CVE-2026-106069 | High | 22, 24, 26 | TLS hostname bypass when a host loosely resolves as an IP address |
The releases also fix medium-severity HTTP keep-alive, certificate-validation, and snapshot entropy bugs, plus Permission Model issues. Bundled c-ares, CA certificates, Undici, OpenSSL, and SQLite components were updated where applicable.
A safe production upgrade checklist#
1. Inventory the executable that is actually running#
Check both host and container workloads:
php -v
php --ini
node -p 'JSON.stringify({version: process.version, executable: process.execPath})'
docker ps --format '{{.Names}}\t{{.Image}}'
Do not rely on a manifest or image tag. Inspect each active container, cron image, worker, queue consumer, and sidecar. Check whether restart policies could revive old containers.
2. Back up for rollback, then update through a supported channel#
Back up application data, configuration, the runtime, and loaded-extension inventory. Prefer operating-system packages, an official installer, or a rebuilt container image. Distributions may backport fixes, so verify the vendor advisory and package revision rather than only php -v.
For containers, rebuild from a fixed base image and scan the result. Our Trivy container scanning guide is a starting point, but confirm the runtime inside the final image because scanner databases can lag.
3. Restart every persistent process#
Restart PHP-FPM pools, Apache workers, Node.js services, PM2 clusters, queue consumers, jobs, and containers. Reloading a reverse proxy is not enough. Restarting also clears PHP worker state left by earlier requests.
4. Verify compatibility and health#
Confirm the version in the environment that serves traffic. For PHP, compare modules, test FPM configuration, database access, and application CLI commands. For Node.js, run tests and exercise decompression, TLS, DNS, and snapshot paths.
Then check:
- Public pages and API health endpoints
- Authentication and administrative redirects
- Upload and multipart handling
- Background jobs and queues
- Database reads and writes
- Reverse-proxy, PHP, Node.js, and application logs
5. Preserve evidence without mistaking errors for compromise#
Historical OOM, fatal-error, decoder, or worker-crash logs increase urgency but do not prove exploitation. Preserve logs, record the patch time, and investigate unexpected processes, modified files, users, persistence, or outbound connections.
Patch the runtime, then prove the worker changed#
Application-layer maintenance is only one layer of patch management. Updated WordPress code can run on vulnerable PHP, a clean npm audit can sit above vulnerable native code, and an installed package cannot replace an already running process. Risk-reduction settings are not complete fixes.
Patch PHP to 8.2.35, 8.3.36, 8.4.27, or 8.5.12 as appropriate. Patch Node.js to 22.23.4, 24.22.1, or 26.12.1. Restart every worker, verify the executable in production, test the real request paths, and retain enough evidence to distinguish a clean upgrade from a possible incident.
Official references#
- PHP 8.2.35 security release
- PHP CVE-2026-109618 advisory
- PHP CVE-2026-109619 advisory
- Node.js October 2026 security releases
- Node.js 22.23.4 release
- Node.js 24.22.1 release
- Node.js 26.12.1 release
- Node.js release schedule
Leave a Reply