Modern web architecture has largely shifted away from traditional monolithic SPAs toward hybrid models where server and client execution environments blend seamlessly. Among these innovations, React Server Components (RSCs) have emerged as a dominant paradigm. Rather than sending static HTML or standard JSON to a browser, RSCs rely on a proprietary streaming format known as Flight.
While Flight successfully handles asynchronous data resolution, lazy-loading component boundaries, and remote procedure call (RPC) references, it also introduces a sophisticated attack surface. In December 2025, security researcher Durgesh Pawar and the wider infosec community exposed a critical architectural blind spot in this transport mechanism: CVE-2025-55182, widely dubbed "React2Shell."
Ranked at a severe CVSS 10.0, this unauthenticated remote code execution (RCE) vulnerability proved that complex, stateful serialization protocols operating at the edge of trust boundaries can introduce systemic risks that outstrip traditional web application vulnerabilities.
Main Facts: What is the Flight Protocol and React2Shell?
To understand how React2Shell functions, one must first look at how React communicates over the wire. When an application built with frameworks like Next.js App Router renders a server component, it does not transmit basic JSON blocks. Instead, it streams a line-delimited format called Flight. Each line represents a self-contained "row" processed dynamically by the client-side React runtime as it arrives.
1:I["./src/components/ClientComponent.js",["chunks/main.js"],"default"]
2:J["$","article",null,"children":"$1"]
0:D"name":"RootLayout","env":"Server"
In this architecture, rows use tags (I for imports, J for JSON virtual DOM trees, D for environment data) and a sophisticated prefix system designated by the $ character. These prefixes direct the parser on how to handle specific data types:
$F: Instantiates a callable Server Reference (an RPC endpoint).$L: Triggers lazy component boundaries.$@: Returns the raw underlying frameworkChunkwrapper object.$:: Executes arbitrary property access paths (e.g.,$1:user:name).
Unlike traditional JSON, which is purely structural data that remains passive when parsed, Flight transmits behavior. It instructs client runtimes on which code modules to download, which endpoints to expose, and how to resolve asynchronous promise chains.
When an attacker gains the ability to manipulate this stream—or inject malformed traversal markers into server-side reply handlers—the line between data ingestion and code execution blurs completely.
Chronology of the Threat: From Disclosure to Exploitation
The timeline surrounding the React2Shell vulnerability highlights the speed at which modern threat actors operationalize critical framework flaws.
- Early December 2025: CVE-2025-55182 (React2Shell) is officially disclosed. Security researchers identify an unauthenticated RCE vulnerability sitting inside the Flight deserialization layer (
ReactFlightReplyServer.js). - Mid-December 2025: The Cybersecurity and Infrastructure Security Agency (CISA) rapidly integrates CVE-2025-55182 into its Known Exploited Vulnerabilities (KEV) catalog. Concurrently, telemetry from threat intelligence firms like Sysdig links in-the-wild exploitation to North Korean state-sponsored actors deploying file-less implants via the Ethereum blockchain ("EtherHiding").
- Late December 2025: Additional vulnerability chains emerge. Researchers identify secondary flaws, including Denial of Service (DoS) vectors through nested promise recursion (CVE-2025-55184) and information disclosure bugs that leak server-side source code (CVE-2025-55183).
- January 2026: Further expansion of the attack surface surface results in memory exhaustion vectors (CVE-2026-23864) and cross-site request forgery (CSRF) bypasses via sandboxed iframe
Origin: nullheaders in Next.js (CVE-2026-27978).
Supporting Data and Technical Mechanics
The core vulnerability in React2Shell resides within getOutlinedModel—specifically inside the server-side reply handling code where deep property paths are resolved via the $:, prefix system.
When the parser processes a reference containing colons (such as $1:__proto__:constructor:constructor), it uses a minimalist, vulnerable loop to traverse the data structure:

for (key = 1; key < reference.length; key++)
parentObject = parentObject[reference[key]];
Crucially, this loop historically lacked a hasOwnProperty validation check. It trusted that keys supplied within the stream belonged directly to the object rather than being inherited from shared prototypes up the chain.
By passing __proto__, an attacker walks effortlessly from a plain JSON object through Object.prototype, reaching the core JavaScript Object constructor, and ultimately landing on the native Function constructor. Because JavaScript’s Function object acts equivalently to eval(), executing arbitrary code payload strings becomes trivial: Function("malicious payload")().
Subsequent CVE Disclosures
Following the initial patch for React2Shell, subsequent security audits highlighted the fragility of stateful serialization parsers.
| CVE Identifier | CVSS Score | Vulnerability Type | Description | Remediation Target |
|---|---|---|---|---|
| CVE-2025-55184 | 7.5 | Denial of Service | Infinite recursion of nested Promises during Server Function deserialization. | React 19.0.2 / 19.1.3+ |
| CVE-2025-67779 | 7.5 | Denial of Service | Incomplete first patch allowing alternative promise recursion loops. | React 19.0.4 / 19.1.5+ |
| CVE-2026-23864 | 7.5 | DoS / Memory Exhaustion | Unbounded request body buffering and zipbomb decompression vectors. | React 19.0.4+ / 19.1.5+ |
| CVE-2025-55183 | 5.3 | Information Disclosure | Crafted requests force server functions to reflect source code during implicit stringification. | React 19.0.1 / 19.1.2+ |
| CVE-2026-27978 | 5.3 | CSRF Bypass | Next.js misinterprets sandboxed iframe Origin: null as missing rather than cross-origin. |
Next.js 16.1.7+ |
Official Responses and Remediation Framework
The React core team released targeted patches beginning in late 2025 (React 19.0.1, 19.1.2, and 19.2.1), followed by subsequent hotfixes for derivative issues.
The primary code fix caches the native hasOwnProperty function reference at module load time to prevent prototype shadowing attacks:
var hasOwnProperty = Object.prototype.hasOwnProperty;
// Enforced check during deserialization traversal
hasOwnProperty.call(value, i);
However, security practitioners emphasize that patching core framework libraries is only half the battle. Because Flight is an inherently complex streaming deserialization model, developers must implement a defense-in-depth architecture across their applications.
Ranked Practical Defenses
- Strict Input Schema Validation: Implement strict validation layers (using Zod or Valibot) at the absolute beginning of every Server Action—before logging or executing any business logic. Avoid destructuring request arguments prior to validation, as this risks interacting with unvalidated payload properties.
- Enforce the
server-onlyPackage: Use theserver-onlypackage to isolate sensitive logic, database queries, and credentials, preventing them from accidentally leaking across client-server boundaries via barrel files. - Hardened CSRF Controls: Explicitly configure secure cookie parameters (
SameSite=Strict/SameSite=Lax), utilize explicit per-session CSRF tokens for state-changing endpoints, and avoid weakening framework protections (such as adding'null'to Next.jsallowedOrigins). - Deploy Development-Time Taint APIs: Leverage React’s experimental
taintUniqueValueandtaintObjectReferenceutilities to catch accidental leakage of sensitive tokens or user records during build and test cycles, keeping in mind that these track object references rather than derived data. - Web Application Firewall (WAF) Tuning: Configure edge security layers to inspect headers, block suspicious prototype pollution sequences (
__proto__,constructor:constructor), and rate-limit abnormally large Server Action requests to mitigate potential decompression bombs.
Implications: The Future of Server-Driven UI
The discovery of React2Shell serves as a stark reminder of historical deserialization vulnerabilities observed across other technology stacks, such as Java’s ObjectInputStream vulnerabilities, Python’s pickle flaws, and classic ASP.NET ViewState exploitation.
Whenever a framework introduces a novel custom wire format to streamline communication between servers and clients, it implicitly assumes that the underlying data channel remains secure and trusted.
As the web industry moves deeper into server-driven UI architectures, relying solely on reactive patches and hoping that a parser can account for every possible edge case is insufficient. Long-term security will require stronger architectural primitives, including cryptographic validation of serialized payloads, signed component trees, and runtime integrity checks on streaming protocols like Flight itself. Until then, engineering teams must maintain continuous vigilance, audit their dependency lockfiles, and treat every external server action payload as untrusted input.

