CVE-2026-109618 & CVE-2026-109619: Two Vulnerabilities Allow Unauthenticated RCE in PHP
Image File
Original HTML

Two critical vulnerabilities, CVE-2026-109618 & CVE-2026-109619, allow unauthenticated remote code execution RCE across nearly 2 million exposed PHP servers. Immediate upgrades to PHP 8.2.35, 8.3.36, 8.4.27, or 8.5.12 are required

TL;DR

On October 21, 2026, the PHP core team issued an out-of-band security release addressing two critical vulnerabilities: CVE-2026-109618 and CVE-2026-109619.

PHP is a widely used server-side language – the engine under WordPress, Magento, Drupal, Laravel and endless custom apps. The root cause is how PHP has historically reacted to running out of memory: it aborts the current work with a `longjmp` (`zend_bailout()`). When that abort happens inside engine code that is mid-operation – in particular the `session.upload_progress` handler, which decodes and rewrites a session during file-upload parsing, before the request’s script runs – it leaves PHP’s internal state inconsistent. The fix makes out-of-memory a recoverable condition instead of an abort, hardens the upload path to tolerate failed allocations, resets global state that startup code relies on, and prevents the upload-progress handler from invoking any class code while it decodes a session.

Fixed in 8.2.35, 8.3.36, 8.4.27, 8.5.12.

Impact

- ~2,000,000 internet-facing PHP servers run versions affected by CVE-2026-109618 and CVE-2026-109619.

- 99.99% of the PHP servers we could identify are unpatched.

- 1.37M (69%) run old PHP versions that will never get an official fix.

- 245 servers show a patched version so far.

Source: Shodan, Oct 21, 2026. This counts only servers that show their PHP version, so the real total is likely higher.

Why Are There Two CVEs?

Although both vulnerabilities stem from the same out-of-memory handling in PHP core, the vendor advisories split them into two independent defects:

- CVE-2026-109618 – RCE via OOM corruption: a use-after-free / memory-corruption flaw. PHP’s `longjmp` on out-of-memory leaves request memory in an invalid state before it is fully initialized, and request shutdown then reads or branches on it. The failing allocation need not be related to the corrupted memory.

- CVE-2026-109619 – RCE via stale global state: a use-after-free flaw. Worker-retained global state – session, error, object and extension state – points into a prior request’s freed memory and is accessed by early-running operations before the next request resets it.

Because each flaw is independently exploitable, two separate CVE identifiers were assigned.

Affected Products

- Product: PHP Core (ext/session, ext/standard)

- Affected Versions: All versions supporting session.upload_progress (PHP 5.4.0 through prior unpatched releases)

- Status: Fixed in 8.2.35, 8.3.36, 8.4.27, 8.5.12

Recommendations

- Immediate Upgrade: Apply the official vendor update to PHP version 8.2.35, 8.3.36, 8.4.27, 8.5.12.

- Access Control: Restrict or remove public access to unpatched PHP instances immediately.

- Caution with PoCs: Do not clone or execute unverified Proof-of-Concept (PoC) scripts or third-party patch scripts circulating on public repositories or social media.

Technical Deep Dive

The fix is a single commit, `01a40e89fb` (“Avoid state corruption via bailout”) by Arnaud Le Blanc and co-authors, closing GHSA-w8hw-w9fx-j79w (CVE-2026-109618) and GHSA-6wmf-4rv5-p3rp (CVE-2026-109619). The PHP 8.2.35 changelog lists both under Core.

Root cause: out-of-memory was handled by `longjmp`

Before the fix, any allocation that crossed `memory_limit` ended in `zend_mm_safe_error()` (`Zend/zend_alloc.c`):

Because `zend_bailout()` never returns, the allocation call that triggered it – an `emalloc`, a hashtable resize, a string grow – does not return to its caller either. Any cleanup, pointer refresh, or state reset that was supposed to run after that allocation is skipped. For ordinary script code that is fine, since the request is ending anyway. It is not fine when the skipped code is engine internals that hold live pointers and have not finished updating their own bookkeeping.

Why `session.upload_progress` is the exposed surface

`session.upload_progress` is enabled by default. When a multipart POST carries a `PHPSESSID` field and a `PHP_SESSION_UPLOAD_PROGRESS` field, the multipart parser (`main/rfc1867.c`) drives a session callback for each upload event – and this runs before the request’s script is compiled, whether or not the page uses sessions.

On each progress tick the handler re-opens the session, decodes it, inserts a progress array, re-encodes the whole session and writes it back, while tracking parts of that array through raw pointers in its per-request state. Every one of those steps allocates, and the amounts are set entirely by the request: the number of upload parts, the length of each part’s field name and file name, and the `PHP_SESSION_UPLOAD_PROGRESS` value all feed the size of what gets allocated and re-encoded.

The authors’ own regression test, `tests/basic/oom_rfc1867_upload_progress.phpt`, documents the condition plainly – it posts uploads shaped to exhaust a small `memory_limit` from inside the handler, and the commit title says what used to go wrong when that happened. The comments in that test read like a catalogue of the inputs that drive the allocation:

The point is not a clever payload; it is that reaching the memory limit here required no authentication, no application cooperation, and no unusual configuration – just a sufficiently large or numerous set of upload parts.

What the patch changes

The fix hardens out-of-memory handling in four places:

1. Memory manager – a new fallible-allocation model (`femalloc` / `safe_ferealloc`, guarded by `ZEND_HAS_OOM()`) returns `NULL` on exhaustion instead of calling `zend_bailout()` – the “Replace bailout on OOM with UnwindExit” change – with a new `memory_hard_limit_percent` giving the recovery path headroom.

2. Multipart parser (`main/rfc1867.c`) – converted to those fallible allocations, checking for exhaustion (`goto oom`) rather than trusting each allocation to succeed.

3. Upload-progress handler – stops forcing the session active regardless of result (it now checks `php_session_initialize()` and returns cleanly on failure), and brackets the operation with a new `in_rfc1867_update` flag that drops the unserializer into an “incomplete classes only” mode, so decoding a session in that pre-script window resolves no classes and runs no autoloaders, `__wakeup()`, `__unserialize()` or destructors.

4. Globals – startup-accessed globals are reset properly, so an early unwind cannot leave the engine reading half-initialized state.

Proof of Concept

We validated the issue without weaponizing it. We built debug PHP from source for both the vulnerable (8.2.34) and patched (8.2.35) releases and ran two checks:

- Trigger: a single unauthenticated multipart upload, shaped to exhaust `memory_limit` from inside the `session.upload_progress` handler (the same inputs PHP’s own `oom_rfc1867_upload_progress` test uses), reaches the out-of-memory window with no authentication and no application cooperation.

- Patch check: running PHP’s own OOM regression tests – the ~77 `oom_*` tests that shipped with the fix – against each build, the patched 8.2.35 passes all of them while the unpatched 8.2.34 fails 7 (the upload-progress session decode, a delayed `__unserialize()`, shutdown-after-OOM, multipart header OOM, and more).

Finding If You’re Affected

- Run php -v on each host and image, and check phpinfo() for the web SAPI, which can differ from the CLI. Include images built outside standard pipelines.

- Check if your PHP servers are publicly facing

We created this tool to help you find if you’re affected.

Conclusions

Critical vulnerabilities in widespread core infrastructure represent an escalating operational risk—a challenge amplified by the speed at which AI models make vulnerability research and exploit generation faster and cheaper. When zero-days or unpatched flaws hit ubiquitous software like PHP, the gap between initial disclosure and effective remediation creates immediate, high-stakes turbulence for organizations worldwide.

The early leak of these PHP vulnerabilities triggered an all-too-familiar “information vacuum.” In the hours preceding official patches, security feeds on platforms like X and LinkedIn were flooded with half-tested mitigations, AI-hallucinated fixes, and dubious detection scripts. This environment creates two major risks:

- Social Engineering of Security Teams: Threat actors routinely exploit early panic by publishing fake PoC exploits, backdoor-laden detection scripts, or untested patches aimed directly at tricking security engineers into compromising their own networks.

- Operational Blind Spots: In the absence of confirmed technical vendor advisories, even well-intentioned community research remains speculative and can lead to ineffective mitigations or unnecessary service downtime.

When high-severity vulnerabilities leak without complete vendor details:

- Prioritize Isolation Over Quick Fixes: If an unpatched service is exposed and vendor guidance is pending, temporarily isolate or take sensitive instances offline rather than applying unverified community scripts.

- Rely Strictly on Official Sources: Trust only vendor-validated advisories, official core repository commits, and verified security advisories before applying fixes or changing system configurations.

- Audit Shadow Assets: Ensure your security operations team has full visibility into where vulnerable runtimes actually live within your infrastructure.

How OX Security Can Help

OX can find every PHP runtime across your container images and cloud workloads, including those deployed outside standard processes, so you know exactly what needs patching.

Class (B2B/B2C)
B2B
Ingest Status
Rewritten
Dedupe hash
408fe14569d6d7532eb9abba330ee544
Press Eligible
Yes
Press Eligible Reason
Manuelle Prüfung nötig. Risiko: MEDIUM. Flags: ['numbers']. Stichprobe: False
Source Name
OX Security
Original Summary

<p>Two critical vulnerabilities, CVE-2026-109618 &#38; CVE-2026-109619, allow unauthenticated remote code execution RCE across nearly 2 million exposed PHP servers. Immediate upgrades to PHP 8.2.35, 8.3.36, 8.4.27, or 8.5.12 are required TL;DR On October 21, 2026, the PHP core team issued an out-of-band security release addressing two critical vulnerabilities: CVE-2026-109618 and CVE-2026-109619. PHP is a widely [&#8230;]</p>
<p>The post <a href="https://www.ox.security/blog/cve-2026-109618-cve-2026-109619-two-vulner… &#038; CVE-2026-109619: Two Vulnerabilities Allow Unauthenticated RCE in PHP</a> appeared first on <a href="https://www.ox.security">OX Security</a>.</p>

Image URL
https://www.ox.security/wp-content/uploads/2026/10/Two-Vulnerabilities-Allow-Unauthenticated-RCE-in-PHP-1.png
Source Node
Content Hash (SHA-256, erste 32 hex)
d6b1e288a22c320194ec3326ba5bc22c