CVE-2026-23864

React Server Components: The Flight to Nowhere (CVE-2026-23864)

Amit Schendel
Amit Schendel
Senior Security Researcher

Jan 29, 2026·6 min read·4 visits

Executive Summary (TL;DR)

React's 'Flight' protocol failed to validate deserialization limits. Attackers can send malicious streams to Next.js/React servers that allocate massive arrays, process infinite BigInts, or traverse `__proto__`. This kills the server instantly. Patched in v19.0.4+.

Multiple Denial of Service (DoS) and Prototype Pollution vulnerabilities exist in the React Server Components (RSC) 'Flight' protocol implementation. These flaws allow attackers to trigger Out-of-Memory (OOM) crashes, excessive CPU consumption, or potentially pollute the object prototype chain via specially crafted RSC stream payloads.

The Hook: The Shiny New Toy with a Rusty Edge

React Server Components (RSC) are the current darling of the frontend world. They promise the best of both worlds: server-side logic with client-side interactivity, seamlessly blended. Frameworks like Next.js have bet the farm on this architecture via the App Router. But magic requires a medium, and for RSC, that medium is the 'Flight' protocol—a custom, streaming serialization format used to sync state between the server and the client.

Whenever a developer says, "We don't need JSON, let's write our own serialization protocol to handle complex object graphs and promises," a security researcher gets their wings. History has taught us that custom serialization is a graveyard of security assumptions. CVE-2026-23864 is the latest tombstone. It isn't just a single bug; it's a structural failure to respect the boundaries of physics (memory) and logic (prototypes) within the react-server-dom packages.

This vulnerability is particularly nasty because it targets the infrastructure itself. It doesn't steal user data directly, but it can knock your entire fleet of Next.js containers offline with a few kilobytes of data. It's the digital equivalent of clogging a toilet with a single paper towel.

The Flaw: Trusting the Client (Again)

The root cause here is the classic "Trust Me Bro" anti-pattern. The RSC server endpoints (typically exposed as Server Actions) accept a stream of data to reconstruct objects, arrays, and function references. The server implementation assumed that the incoming stream would play nice. Spoiler: it didn't.

1. The Memory Black Hole (OOM): The server parser allowed the client to specify the size of an array before providing the elements. If the client sent a payload saying, "I'm about to give you an array with 10 billion items," the server dutifully attempted to allocate that memory space immediately. This leads to an instant JavaScript heap out of memory crash.

2. The CPU Burn (BigInt): JavaScript supports BigInt for arbitrary-precision integers. The key word is arbitrary. The vulnerable parser didn't place a limit on the number of digits in a BigInt literal. An attacker could send a string representing a number with millions of digits. The single-threaded Node.js event loop would then lock up trying to parse this mathematical monstrosity, causing a denial of service.

3. The Prototype Pollution: The fulfillReference logic allowed the client to specify paths to resolve within an object. It did not block the __proto__ key. This meant an attacker could traverse up the prototype chain and potentially pollute the base Object.prototype, which is the holy grail for logic bypasses in JavaScript.

The Code: Anatomy of a Fix

Let's look at the smoking gun in the react-server-dom-webpack (and related) packages. The fix involved adding sanity checks that should have been there from day one.

The Prototype Fix: In the original code, the resolution logic blindly followed the path provided by the client stream. The patch introduces a hard check for __proto__ and ensures we are only assigning to "own" properties.

// BEFORE: Blind traversal
// value = value[path[i]];
 
// AFTER: Trust, but verify
const __PROTO__ = '__proto__';
if (key === __PROTO__) {
  // Nice try, hacker.
  return undefined;
}
if (hasOwnProperty.call(value, key)) {
  value = value[key];
} else {
  throw new Error('Invalid reference.');
}

The Resource Limits: Meta also introduced explicit constants to cap the madness. They realized that legitimate web applications rarely need to process numbers larger than the atoms in the universe.

const DEFAULT_MAX_ARRAY_NESTING = 1000000;
const MAX_BIGINT_DIGITS = 300;
const MAX_BOUND_ARGS = 1000;

If your application logic relies on a BigInt with more than 300 digits, you aren't building a website; you're simulating dark matter physics, and you should probably do that in C++.

The Exploit: Killing the Server

Exploiting this requires understanding the RSC wire format, but you don't need to be a wizard. You just need to send a malformed POST request to the server endpoint handling RSC actions.

Scenario 1: The OOM Crash We construct a payload that defines a massive array. The format typically looks like a line-delimited list of JSON-like structures. We define a reference $A that claims to be a sparse array of doom.

POST /my-server-action HTTP/1.1
Content-Type: text/x-component
 
1:["$A", 9999999999]

When the V8 engine underneath Node.js tries to allocate a sparse array of this magnitude, it panics and crashes the process. In a containerized environment (like Kubernetes), the pod dies and restarts. If the attacker keeps sending these requests, the service enters a CrashLoopBackOff state.

Scenario 2: The CPU Freeze We target the BigInt parser. The format uses $n to denote a BigInt.

POST /my-server-action HTTP/1.1
 
0:"$n9999999999...[repeat 1 million times]"

The server receives this, sees the $n marker, and hands the massive string to the BigInt() constructor. The CPU spikes to 100%, requests pile up, and the load balancer eventually marks the instance as unhealthy.

The Impact: Asymmetric Warfare

The danger of CVE-2026-23864 lies in its asymmetry. It costs an attacker effectively zero resources to generate these payloads—a simple Python script with a loop will suffice. However, the impact on the target is catastrophic resource exhaustion.

While Denial of Service is often dismissed as "just downtime," in the context of serverless functions (like Vercel or AWS Lambda) or auto-scaling clusters, this translates directly to financial damage. You are paying for the CPU cycles the attacker is forcing you to burn. Furthermore, the Prototype Pollution aspect (__proto__) is a sleeper agent. Depending on the other libraries present in your Node.js environment, polluting the prototype could lead to bypasses in authentication middleware, NoSQL injection, or other Remote Code Execution (RCE) gadgets.

This isn't just about crashing; it's about the instability of the foundation your shiny new React app sits on.

The Fix: Stop the Bleeding

The mitigation is straightforward: Update your dependencies. This isn't a configuration tweak; the code itself was broken. You need to pull the patched versions of react-server-dom-webpack, react-server-dom-turbopack, or react-server-dom-parcel.

Fixed Versions:

  • 19.0.4
  • 19.1.5
  • 19.2.4

If you are using Next.js, updating to the latest patch release should pull these in transitively. Verify your package-lock.json or yarn.lock to ensure the deeply nested react-server-dom-* packages are actually updated. Don't trust the top-level version number; check the lockfile.

If you cannot update immediately (why?), you could theoretically deploy a WAF rule to inspect the body of POST requests to Server Action endpoints, specifically looking for the string __proto__ or regex-matching effectively long numeric sequences after $n. But that is a band-aid on a bullet wound. Just update.

Fix Analysis (1)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
0.60%
Top 31% most exploited
500,000
via Shodan

Affected Systems

Next.js Applications (App Router)Remix Framework (Future RSC support)React Server Components (Custom Implementations)react-server-dom-webpackreact-server-dom-turbopackreact-server-dom-parcel

Affected Versions Detail

Product
Affected Versions
Fixed Version
react-server-dom-webpack
Meta
19.0.0 < 19.0.419.0.4
react-server-dom-webpack
Meta
19.1.0 < 19.1.519.1.5
react-server-dom-webpack
Meta
19.2.0 < 19.2.419.2.4
AttributeDetail
CWE IDsCWE-502 (Deserialization), CWE-400 (Resource Exhaustion)
Attack VectorNetwork (HTTP POST)
CVSS v3.17.5 (High)
EPSS Score0.00603 (68.98%)
Exploit StatusPoC (Private)
ProtocolReact 'Flight' RPC
CWE-502
Deserialization of Untrusted Data

Deserialization of Untrusted Data causing Resource Consumption

Vulnerability Timeline

Vulnerability Disclosed & Patched
2026-01-26
NVD Published
2026-01-27

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.