While React Server Components rely on the custom Flight protocol to stream interactive user interfaces, this exact mechanism introduces powerful deserialization sinks that malicious actors can exploit. Security researcher Durgesh Pawar has broken down the mechanics behind the CVSS 10.0 "React2Shell" vulnerability, demonstrating how protocol manipulation can lead directly to remote code execution. The analysis also outlines a practical, ranked set of defenses—ranging from strict schema validation to cross-site request forgery hardening—designed to secure React applications against these inherent structural risks.
React Server Components do not send traditional HTML to the browser, nor do they send standard JSON. When a server component renders, the data traveling over the wire is a custom streaming protocol known as Flight. It is a line-delimited format featuring its own distinct type system, reference resolution rules, and mechanisms for reconstructing executable behavior directly on the client side.
Despite its central role in modern web applications, most React developers rarely open their browser network tabs to inspect a Flight payload. It typically resembles a mixture of JSON fragments, dollar-sign-prefixed references, and module pointers that the React runtime silently reassembles into a live component tree. Because the framework manages this process seamlessly behind the scenes, few teams have questioned what that underlying trust actually implies.
The security implications of this architecture came into sharp focus following the disclosure of CVE-2025-55182 in December 2025. Quickly dubbed "React2Shell" by the security community, the vulnerability exposed a CVSS 10.0, unauthenticated remote code execution flaw sitting directly within the Flight deserialization layer. A single crafted HTTP request directed at a Server Function endpoint granted attackers full shell access without requiring any credentials whatsoever.
The Cybersecurity and Infrastructure Security Agency promptly added the flaw to its Known Exploited Vulnerabilities catalog. Concurrently, security firm Sysdig tied in-the-wild exploitation to North Korean state-sponsored actors who deployed file-less implants via the Ethereum blockchain. A vulnerability of this severity naturally commands the immediate attention of engineering and security teams alike.
A closer inspection of the React source code, specifically within the getOutlinedModel and getChunk functions where core resolution logic resides, reveals that React2Shell was not merely a localized parsing bug. Rather, it served as a symptom of a broader architectural reality. Flight reconstructs executable references, lazy-loaded components, server remote procedure call endpoints, and asynchronous state directly from a stream of text. That functionality forms a fully fledged deserialization system. Consequently, the attack surface extends well beyond a single missing property check, involving complex interactions between wire formats, deserialization sinks, and runtime behavior.
To understand how these vulnerabilities arise, it is necessary to examine how Flight operates on the wire. Inspecting network traffic on a Next.js App Router page reveals requests returning the text/x-component content type. Instead of a single JSON blob, Flight uses a streaming, line-delimited format where each line represents a self-contained row processed by the client-side React runtime as it arrives.
Every row follows a strict syntax combining a numeric row ID, a tag indicating the data type, and a payload. These tags categorize data into JSON virtual DOM nodes, module metadata, import directives, resource prefetching hints, server environment context, and serialized exceptions. However, the true complexity and underlying attack surface reside within the protocol’s prefix system.
When the client-side parser encounters string values beginning with a dollar sign, it intercepts them, checks the prefix, and routes the data through type-specific resolution paths. For example, specific prefixes resolve model references, native JavaScript symbols, callable server actions, lazy component boundaries, raw chunk wrappers, and binary data blobs.
Among these, property access prefixes allow the protocol to specify deeply nested paths, instructing the parser to traverse properties dynamically based on data arriving in the stream. If security auditors have learned anything from analyzing prototype pollution vulnerabilities in JavaScript, it is that dynamic property traversal driven by untrusted input demands rigorous validation.

Historically, languages like Java, Python, PHP, and .NET have grappled with severe deserialization vulnerabilities where attacker-controlled input triggers executable behavior during reconstruction. JavaScript developers long assumed their ecosystem was immune to these classes of bugs because standard JSON parsing produces plain data objects without invoking constructors or magic methods. While raw JSON parsing remains safe, that protection dissolves the moment a framework wraps custom deserialization logic around the parser.
This dynamic underpins the security challenges within Flight. Because the protocol deserializes behavior rather than mere data, its control flow is driven entirely by the contents of the stream. If an attacker gains influence over the stream’s content, they effectively control which functions the parser calls, which objects it constructs, and what internal state gets exposed.
The mechanics of React2Shell demonstrated these risks in practice. Located in the server-side reply handling code, the vulnerability centered on the function responsible for resolving deep property paths from the reference system. When encountering a property reference, the parser split the string on colons and walked the path segment by segment through a loop devoid of any ownership validation.
By supplying a malicious path, an attacker could traverse from a plain JSON object up through the object prototype to the constructor and ultimately access the Function constructor, which behaves similarly to an evaluation utility. Chaining this capability with other protocol features allowed attackers to transform arbitrary property traversal into remote code execution.
The immediate exploitation observed in the wild underscored the urgency of remediation. State-sponsored threat actors swiftly weaponized the flaw, deploying sophisticated file-less implants and encrypted backdoors that blended into compromised Linux systems. Researchers documented encrypted communications and advanced evasion techniques, proving that unauthenticated deserialization vulnerabilities remain among the most dangerous vectors facing modern web infrastructure.
In response, the React team issued targeted patches that cache the genuine property ownership verification method at module load time, invoking the cached reference for every property check during deserialization. Even if an attacker attempts to shadow ownership verification methods on malicious objects, the runtime relies on the original prototype method, effectively blocking the specific prototype traversal path exploited in React2Shell. These fixes shipped across multiple minor and patch releases, prompting urgent updates across the web development ecosystem.
While the framework-level patches successfully closed the known gadget chain, they left the underlying property traversal model intact, prompting security experts to emphasize the need for robust application-level defenses. Primary among these recommendations is rigorous input validation on all server actions. Because the Flight deserializer processes raw, unvalidated network input before application code takes control, schema validation libraries such as Zod or Valibot must be implemented at the very beginning of every server action handler before any business logic or logging executes.
Additionally, development teams have been advised to leverage structural safeguards like the server-only package to prevent sensitive server-side modules from accidentally being imported into client-side code. However, experts warn that such packages only protect code from crossing boundaries, not the raw data returned by server functions, necessitating careful filtering of return shapes. Furthermore, engineering teams must maintain robust cross-site request forgery protections, configure strict cookie policies, and avoid weakening default framework security settings.
As web architectures continue to evolve toward server-driven user interfaces, the lessons learned from the Flight protocol highlight the ongoing challenges of securing complex deserialization layers. While framework maintainers and security researchers continue to address individual vulnerabilities as they emerge, the broader industry conversation increasingly centers on the need for stronger architectural primitives, cryptographic validation of serialized payloads, and comprehensive content integrity checks to ensure the security of modern web applications.
