
Recently, JFrog Security has been tracking two CRITICAL-severity PHP core vulnerabilities (CVE-2026-109618, CVE-2026-109619), disclosed today and referred to publicly as PHP2Shell. The bugs allow unauthenticated remote code execution and Heartbleed-style memory disclosure in PHP itself, independent of the application running on top of it. In this write-up, we will discuss the bug, the exploit, its mechanics, and the prerequisites required for it to be exploitable.
On October 20, the PHP security team announced an upcoming security release scheduled for October 21 at 14:00 UTC. The release was expected to address two critical vulnerabilities, CVE-2026-109618 and CVE-2026-109619, each assigned a CVSS v4.0 score of 9.2.

The timing created a difficult situation for defenders. Organizations have been warned about critical vulnerabilities in one of the web's most widely deployed server-side technologies, but the official technical details and fixed versions have not yet been published. Meanwhile, researchers have been investigating the issues, and reports of a potential exploit have already emerged.
PHP versions:
- PHP 8.2.x before 8.2.35
- 8.3.x before 8.3.36
- 8.4.x before 8.4.27
- 8.5.x before 8.5.12
Configuration:
session.upload_progress.enabled=On (factory default) and multipart uploads accepted.
Server Environment:
Apache mod_php (and likely FrankenPHP) for the confirmed application-independent RCE. FPM is susceptible through state published after successful startup.
- Upgrade to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35.
- If you cannot upgrade: according to the PHP security advisories 1, 2 you can partially mitigate by setting
session.upload_progress.enabled=0(andfatal_error_backtraces=0on PHP 8.5.x) administratively, restarting every worker after changing them, and enforcingmemory_limit=-1(do not useRLIMIT_AS/RLIMIT_DATA). Settingpm.max_requests=1additionally breaks the same-worker requirement. Note that the upload-progress switch does not affect the OPcache or backtrace arms, and thatmemory_limit=-1removes the resource-exhaustion protection. Each measure is partial on its own. - JFrog Xray users are protected. Xray flags PHP versions in the affected ranges in scanned artifacts and dependencies.
Later that day, Wiz confirmed these are CVEs they found alongside Calif (A security research lab), and OpenAI as part of the Patch the planet initiative.
JFrog’s team was able to discover the general flow of these vulnerabilities before it was published and reach several working POC’s. We concluded that the vulnerability flow probably looked like this:
- PHP has a mechanism to process multipart POST requests; it creates a session file on the disk to track the upload progress. The user controls the session ID (sent as a normal POST field PHPSESSID), the suffix of the session key inside the file (PHP_SESSION_UPLOAD_PROGRESS), and the uploaded filename, which is stored as-is, letting him insert potentially malicious data into the file.
- The session file is always stored in a serialized format. When the PHP engine opens the session, it unserializes the file's content before any script runs. The decoder trusts whatever it finds: it does not verify that the bytes came from PHP itself, so data the user influenced through the upload is decoded as live session data.
- The unserialization is not a simple parser: while it runs, PHP builds zvals (the structures PHP uses to store dynamic values, allocating and freeing memory in the process) and tracks them in a bookkeeping struct that remembers the values it built, for references and destructors. This bookkeeping assumes that every initialization is paired with a cleanup inside the same request.
- Another multipart upload handled by the same worker, which opens the session before any script runs, decodes this file again. The first decode broke the pairing from #3: an error skipped the cleanup, so PHP's globals still point at the freed bookkeeping memory. The second upload's allocations take over that memory, its decode runs on attacker-controlled bytes, and the session write back calls the fake object's serialize function, ending with control of the RIP register.
The vulnerabilities enable the creation of the following exploits:
- Remote Code execution
- Information disclosure
Whereas both vulnerabilities can be used to achieve either.
The two advisories describe the same defect from two angles:
CVE-2026-109618: Saves request-owned memory pointers in persistent variables, leading to use-after-free RCE or memory leaks when a fatal error occurs and a subsequent request trusts the stale pointer.

CVE-2026-109619: Follows the same pattern across other persistent variables, including saved fatal error backtraces in PHP 8.5 and OPcache shared-memory state corrupted across workers.

The following was the fix shipped by the PHP team:

The fix addresses the following:
- OOM no longer aborts mid-operation (31c0ea7d7ff): the UAF existed because a fatal OOM longjmped straight out of the code that was about to clear the pointer. Now OOM becomes a soft error at the next VM safe point (or a hard _exit()** past a higher threshold), so the cleanup always runs and the pointer is always cleared before the memory is freed.
- Defense in depth: even when a request dies another way, all long-lived state (backtrace, OPcache, session, error state) is reset at shutdown, so nothing stale survives into the next request.
- No user code during upload-progress decode: objects decoded by the upload-progress handler stay __PHP_IncompleteClass - no autoload, no __destruct(), so the object-injection delivery verified in this post is closed too.
While investigating PoCs published on GitHub, we found that some users were taking advantage of the opportunity to spread fake PoCs as pranks.
One such repository hides a Base64-encoded string that, at first glance, appears to decrypt and execute a malware payload. However, our investigation confirmed that this is not actual malware. Instead, the script appears to change the victim's wallpaper to NSFW content.
JFrog is tracking both vulnerabilities and helping organizations prepare to respond.
JFrog Xray and Catalog already includes CVE-2026-109618 and CVE-2026-109619 in its vulnerability intelligence, helping teams identify these issues through their existing security workflows.


Additionally, our security team has deployed contextual scanners to the determine the applicability of these CVEs for customers of JFrog Advanced Security.
JFrog XRAY IDs
| OS / Platform | CVE-2026-109618 | CVE-2026-109619 |
|---|---|---|
| Oracle | XRAY-1141250 | XRAY-1141258 |
| Amazon | XRAY-1141248 | XRAY-1141256 |
| Suse | XRAY-1141245 | XRAY-1141253 |
| Ubuntu | XRAY-1141247 | XRAY-1141255 |
| Alpine | XRAY-1141243 | XRAY-1141251 |
| RedHat | XRAY-1141249 | XRAY-1141257 |
| Minimos | XRAY-1141246 | XRAY-1141254 |
| Debian | XRAY-1141737 | XRAY-1141738 |
| Cpp | XRAY-1141244 | XRAY-1141252 |
