Feb 15, 2026·6 min read·116 visits
Critical Race Condition in Chrome's V8 engine involving `ReadableStream` and `SharedArrayBuffer`. Allows remote attackers to bypass the V8 Sandbox and achieve RCE via a crafted HTML page. Patched in Chrome 139.0.7258.127.
A high-severity race condition in Google Chrome's V8 JavaScript engine allows attackers to bypass the V8 Sandbox and execute arbitrary code. By exploiting the interaction between `ReadableStream` consumers and `SharedArrayBuffer`, attackers can corrupt heap memory via a data race, effectively turning a browser tab into a foothold for system compromise. This vulnerability was successfully demonstrated in v8CTF by researcher Seunghyun Lee.
JavaScript is famously single-threaded. It’s the one thing that keeps browser exploit development somewhat sane—you generally know the state of the world when your code executes. But then came SharedArrayBuffer (SAB). SABs are the chaotic evil of the JavaScript world because they allow true concurrency. They let the main thread and a Web Worker shout at the same chunk of memory simultaneously.
Now, enter ReadableStream. Streams are designed to pipe data efficiently, often optimized in C++ within the V8 engine. V8 developers assume that when they are reading a buffer, the floor won't drop out from under them. They assume stability.
CVE-2025-8880 is what happens when that assumption meets reality. It’s a race condition where the engine tries to consume a stream backed by shared memory, but a concurrent thread modifies that memory state mid-consumption. This isn't just a crash; it's a high-precision tool to break the V8 Sandbox, the security boundary Google built specifically to stop us from doing exactly this.
The vulnerability (CWE-362) lies in the synchronization—or lack thereof—between the ReadableStream implementation and the underlying buffer storage when that storage is a SharedArrayBuffer.
In a typical Time-of-Check to Time-of-Use (TOCTOU) scenario, the engine checks the length of the data to ensure it's safe to read. It says, "Okay, this buffer is 1024 bytes. I will read 1024 bytes." It then proceeds to the read operation.
However, because the backing store is shared, a malicious Web Worker running in the background can modify the buffer or detach it in the nanoseconds between the check and the use. If the worker shrinks the buffer or creates an inconsistent state exactly when the stream consumer (the C++ side) is processing it, V8 ends up reading or writing to memory that no longer belongs to that buffer. This results in memory corruption on the V8 heap.
To understand the fix, we have to look at what was missing. The patch series (CL 6787532, 6811146) introduces memory barriers and explicit locking mechanisms during stream consumption.
The vulnerable logic looked something like this (pseudocode representation of V8 internal logic):
// VULNERABLE LOGIC
void ReadableStream::PullFromSource() {
// 1. Get pointer to buffer
void* data = buffer->data();
// 2. Get length
size_t len = buffer->byte_length();
// ... minimal context switch ...
// 3. Read data assuming 'len' is valid for 'data'
memcpy(destination, data, len);
}If a Web Worker thread resizes or detaches the buffer between step 2 and step 3, len is now stale, and memcpy goes out of bounds. The fix involves ensuring that the buffer cannot be modified while the stream is locking it for a read operation, effectively serializing the access.
> [!NOTE]
> The patch introduces v8::internal::SharedMutex usage in streams.cc to ensure that ReadableStream operations hold a read lock on the backing store, preventing the SAB from mutating under its feet.
This is where Seunghyun Lee (@0x10n) earned his paycheck. Exploiting a race condition in a browser is technically demanding because you have to win the race consistently. The exploit strategy likely involves the following chain:
SharedArrayBuffer and wrap it in a ReadableStream.Response object or a TextDecoder) that will read from the stream.By carefully arranging the heap (Heap Feng Shui), the attacker places a victim object (like an Array or an Object) immediately after the SAB. The out-of-bounds write overwrites the map or elements pointer of the victim object.
Once you have corrupted an object's pointer, you can create a "fake object" primitive. In modern V8, this allows you to read/write anywhere inside the V8 Sandbox. However, because this specific bug corrupts the underlying backing store management, it provides a bridge to write outside the sandbox, leading to full RCE.
Why is this critical? Modern browsers use a technique called the "V8 Sandbox" to contain exploits. Even if you get code execution in JavaScript, you are supposed to be trapped in a 4GB virtual address space, unable to touch the rest of the renderer process.
CVE-2025-8880 is a Sandbox Escape. It breaks the containment vessel. An attacker who exploits this can:
The fact that this was demonstrated in v8CTF proves it is weaponizable. It's not theoretical.
Google patched this in Chrome version 139.0.7258.127. If you are running anything older, your browser is a ticking time bomb waiting for a malicious ad or a compromised website.
Remediation Steps:
chrome://settings/help and ensure you are on the latest stable channel.SharedArrayBuffer usage via the SharedArrayBufferEnabled enterprise policy, though this will break sites like Google Earth, Figma, and heavy web games.For Developers:
This is a stark reminder that SharedArrayBuffer introduces hard concurrency problems into a language that wasn't originally designed for them. If you are writing native modules or working on JS engines, never trust the length of a shared buffer to stay constant across a function call.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Google Chrome Google | < 139.0.7258.127 | 139.0.7258.127 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-362 (Race Condition) |
| CVSS v3.1 | 8.8 (High) |
| Attack Vector | Network (Web) |
| Privileges Required | None |
| User Interaction | Required (Visit Page) |
| Impact | Remote Code Execution / Sandbox Escape |
Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')
CVE-2026-115895 is a high-severity code injection vulnerability (CWE-94) in the happy-dom npm package prior to version 21.0.4. The vulnerability exists within the ECMAScriptModuleCompiler component, which transforms ECMAScript module syntax into executable Node.js functions when JavaScript evaluation is enabled. Due to an incomplete fix for CVE-2026-33943, the compiler failed to validate local named import aliases against legal JavaScript identifier rules. Attackers supplying crafted module imports—specifically utilizing destructuring default initializers alongside JSON module attributes—can inject arbitrary JavaScript expressions directly into the host Node.js runtime context.
An improper input validation and authorization bypass vulnerability exists in the LangGraph storage layer affecting langgraph, langgraph-checkpoint-postgres, and langgraph-checkpoint-sqlite. Because relational store implementations serialize namespace tuples into dot-delimited strings without validating labels on read, search, delete, and batch operations, an attacker who controls a namespace label can inject periods (.) to traverse namespace boundaries and access, modify, or delete data belonging to other namespaces.
CVE-2026-115886 (GHSA-2wqp-q3c6-ccj5) is a Server-Side Request Forgery (SSRF) and Unsafe Reflection vulnerability in MLflow versions 3.12.0rc0 prior to 3.17.0. Unauthenticated REST API endpoints accept serialized third-party scorer JSON payloads that are dynamically deserialized and reflectively instantiated without sanitizing constructor keyword arguments. When optional dependencies such as trulens and trulens-providers-litellm are installed, attackers can inject egress-steering arguments into the scorer payload, forcing the MLflow server to dispatch outbound HTTP requests to arbitrary internal destinations or cloud metadata services.
CVE-2026-113872 (GHSA-q7qp-rjg7-q26m) is a high-severity denial-of-service vulnerability affecting the multer multipart/form-data upload middleware for Node.js and Express in versions 2.0.0 through 2.4.0. When an endpoint is configured to accept multiple files using an asynchronous fileFilter callback, a crafted, truncated multipart HTTP request can trigger an unhandled error event on the underlying busboy stream parser after request teardown has already completed. Because all error listeners are stripped during teardown, Node.js treats the resulting error event as an uncaught exception and immediately terminates the server process.
CVE-2026-115897 (also tracked as GHSA-m5mm-p8h7-m29v and aliased as CVE-2026-115754) is a Cross-Site Scripting (XSS) vulnerability in the Yahoo serialize-javascript npm package prior to version 7.1.3. The flaw exists in the regular expression used by escapeFunctionBody() to neutralize HTML script closing tags within serialized JavaScript functions. Because function bodies are sanitized in isolation before structural formatting is applied, a function whose string representation terminates directly with the sequence '</script' bypasses the positive lookahead check. When combined with serialization formatting options that introduce whitespace delimiters and a subsequent property that supplies a closing bracket, an attacker can prematurely terminate an enclosing HTML <script> block and inject arbitrary HTML or JavaScript into the rendered document.
CVE-2026-109841 is a Subresource Integrity (SRI) verification bypass vulnerability in undici, the official HTTP/1.1 and HTTP/2 client library for Node.js that powers the global fetch() implementation. The flaw stems from improper handling of case sensitivity (CWE-178) when validating cryptographic hash algorithm tokens within SRI metadata. Because undici compared incoming algorithm identifiers against a strictly lowercase set without prior ASCII-lowercase normalization, valid uppercase or mixed-case tokens such as SHA256- or Sha384- were treated as unrecognized algorithms and discarded. Under SRI forward-compatibility rules, discarding all provided tokens results in an empty integrity list, causing undici to fail open and accept tampered HTTP response bodies without cryptographic verification.