The "Black October" Runtime Crisis: PHP2Shell, Unpatched CVE-2026-115560 & HTTP2Shell Polyglot Brotli RCE (CVE-2026-111497)
CVE-2026-109618, CVE-2026-109619, CVE-2026-115560 & CVE-2026-111497 (CWE-416 (Use After Free), CWE-502 (Unsafe Deserialization) & CWE-787 (Out-of-Bounds Write))
Severity: CRITICAL ("BLACK OCTOBER" RUNTIME EMERGENCY) (CVSS 9.2 – 9.8)
Threat Actor: Global Botnets, Opportunistic Ransomware Affiliates & AI-Mutating Exploit Swarms
Status: Active Mass Exploitation in the Wild; Urgent CISA Alert Issued Oct 23, 2026
Affected Systems: PHP 5.4–8.5 | Google Brotli C Decoder 1.0.3–1.2.0 (Node.js, Python, Java brotli4j, Bun, Envoy, Rust FFI)
Fixed In: PHP 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 (+ php.ini mitigation) | libbrotli 1.2.1+ | Node.js 22.23.4 / 24.22.1 / 26.12.1
If you want to understand why security leaders from Anthropic, Cloudflare, and OpenAI spent the weekend warning of an AI-driven "vulnerability tsunami" during "Black October," look no further than the simultaneous collapse of memory safety across the internet’s two most ubiquitous HTTP request-processing paths: PHP multipart session upload progress and Google’s C Brotli decompression library. Over the past 96 hours, defenders have had to contend not only with active mass exploitation of PHP2Shell (CVE-2026-109618 and CVE-2026-109619) and a CISA emergency directive on October 23, but also with an unpatched follow-up PHP session deserialization vector (CVE-2026-115560) and the rapid expansion of Node2Shell into HTTP2Shell (CVE-2026-111497)—an out-of-bounds heap write in libbrotlidec that crosses FFI and JNI boundaries into Python, Java, Node.js, Bun, and C++ proxies.

1. PHP2Shell (CVE-2026-109618 & CVE-2026-109619): AI-Discovered Pre-Script Heap UAF
Discovered in August 2026 by researchers from Wiz, OpenAI, and Calif using frontier AI models to audit complex C pointer lifetimes across PHP’s request initialization (RINIT) phase, CVE-2026-109618 and CVE-2026-109619 (both CVSS 9.2) reside in main/rfc1867.c and ext/session/session.c. Because default php.ini configurations ship with session.upload_progress.enabled = 1, sending a multipart/form-data HTTP POST request containing a field named PHP_SESSION_UPLOAD_PROGRESS forces the PHP engine to initialize the session and populate $_SESSION["upload_progress_..."] before a single line of userland PHP code executes.
- CVE-2026-109618 (HashTable Reallocation Dangling Pointer): During multipart boundary parsing,
php_session_rfc1867_callbackcaches rawzval*pointers referencing internal array elements inside$_SESSION. By crafting a multipart stream that triggers a ZendHashTableresize/reallocation mid-upload, the underlyingarDatabucket buffer is freed and moved while the cachedzval*pointer remains dangling—yielding a deterministic pre-auth Heap Use-After-Free (CWE-416). - CVE-2026-109619 (OOM Bailout Teardown Corruption): When an attacker pairs multipart upload progress with an engineered memory-limit exhaustion trigger (
zend_bailout()), PHP skips standard RFC1867 cleanup handlers while retaining corrupted pointer references during request shutdown (RSHUTDOWN).
After exploit details leaked prematurely, Amazon MadPot honeypots recorded active exploitation starting October 17, and Cloudflare—which deployed emergency WAF rules nine hours ahead of the October 21 patch—observed attackers using automated tooling to dynamically mutate multipart boundaries and field encodings in real time to probe WAF filters.
2. The Follow-Up Shock: Unpatched PHP CVE-2026-115560 (Session Serializer Confusion)
Just 48 hours after shipping PHP 8.5.12, 8.4.27, 8.3.36, and 8.2.35 to fix PHP2Shell, the PHP group and security researchers disclosed CVE-2026-115560 on October 23—an unpatched Remote Code Execution vector affecting even the newly patched PHP builds when specific runtime configuration patterns are present.
// Vulnerable pattern in userland PHP applications / legacy CMS plugins:
// 1. php.ini starts request in RINIT with default: session.serialize_handler = php
// Attacker sends multipart PHP_SESSION_UPLOAD_PROGRESS with payload: "|O:8:"Exploit":..."
// 2. Later during script execution, the application dynamically switches handlers:
ini_set('session.serialize_handler', 'php_serialize');
session_start(); // Or subsequent request deserializes the mismatched '|' delimiter!
Because PHP_SESSION_UPLOAD_PROGRESS runs during RINIT (before the script’s ini_set() call), the session payload is written or queued under the default php serializer format (which uses the pipe character | as a key-value delimiter) while the application reads or persists the session under php_serialize. Injecting a pipe-prefixed serialized object string (|O:...) into the upload progress filename or identifier causes PHP to instantiate arbitrary POP-chain gadgets in memory—achieving unauthenticated RCE without needing memory corruption.
3. From Node2Shell to HTTP2Shell (CVE-2026-111497): Polyglot Brotli Heap Overflow
While PHP admins scrambled over the weekend, backend teams running Node.js, Python, and Java discovered that CVE-2026-111497 (CVSS 9.2/9.8)—initially dubbed Node2Shell when Node.js patched its bundled Brotli library—actually resides in upstream Google Brotli 1.0.3 through 1.2.0 (c/dec/decode.c). Specifically, an integer calculation flaw during backward-reference distance and ring-buffer window expansion triggers an Out-of-Bounds Heap Write (CWE-787) when unpacking a maliciously crafted Brotli stream (Content-Encoding: br).
Why does a C buffer overflow hit "memory-safe" languages like Python and Java? Because high-throughput HTTP frameworks bind directly to native libbrotlidec via FFI/JNI for wire-speed decompression:
- Node.js & Bun: Express 5,
body-parser, Undicifetch(), and Next.js pipeContent-Encoding: brstreams directly intonode:zlib’s C++ wrapper aroundc/dec/decode.c. Fixed in Node.js 22.23.4, 24.22.1, 26.12.1 and Bun 1.4.4. - Python (Silent Auto-Activation): Whenever the C-extension wheel
brotliorbrotlicffi(versions< 1.2.1) is present anywhere insite-packages(often pulled transitively),urllib3,requests,aiohttp, andhttpxautomatically advertiseAccept-Encoding: brand feed untrusted responses straight into the vulnerable C heap! - Java / JVM (
brotli4jJNI): While pure-Javaorg.brotli:decis safe from native RCE, Netty (HttpContentDecompressor), Reactor Netty, Spring WebFlux / Cloud Gateway, and Vert.x automatically loadcom.aayushatharva.brotli4j:brotli4jif on the classpath—unpacking nativelibbrotlidec.sointo/tmpvia JNI and exposing the JVM process heap.
Detection Telemetry & Emergency Mitigation
# 1. PHP: Neutralize BOTH PHP2Shell (CVE-2026-109618/19) AND unpatched CVE-2026-115560 in php.ini
echo "session.upload_progress.enabled = 0" | sudo tee -a /etc/php/*/fpm/conf.d/99-disable-upload-progress.ini
sudo systemctl reload php*-fpm
# 2. Nginx Edge Mitigation: Block multipart upload_progress & strip inbound Brotli encoding
# Inside server {} or http {} block:
if ($http_content_encoding ~* "br") { return 415; }
# 3. Audit Python environments for vulnerable native Brotli C extensions (< 1.2.1)
python3 -c "
for mod in ('brotli', 'brotlicffi'):
try:
m = __import__(mod)
print(f'[ALERT] {mod} installed at {m.__file__} (version: {getattr(m, "__version__", "unknown")})')
except ImportError:
print(f'[OK] {mod} not present')
"
# 4. Audit Java classpath / containers for JNI brotli4j native JARs
find / -name "*brotli4j*.jar" -o -name "libbrotlidec.so*" 2>/dev/nullRemediation Checklist
- Patch PHP & Disable Upload Progress: Upgrade to PHP 8.5.12, 8.4.27, 8.3.36, or 8.2.35 immediately and set
session.upload_progress.enabled = 0across all productionphp.inifiles. - Upgrade Brotli Across All Stacks: Update system
libbrotlipackages to 1.2.1+ (or backported distro fixes), upgrade Node.js to 22.23.4 / 24.22.1 / 26.12.1, upgrade Pythonbrotli/brotlicffito 1.2.1+, and update Javabrotli4jto 1.20.0+. - Hunt for Post-Exploit Web Shells & Child Processes: Alert on
php-fpm,httpd,node,python, orjavaworker processes spawning/bin/sh,bash,curl, orwget.