Weaponizing and Defending the React Flight Protocol

While React Server Components (RSCs) leverage the custom Flight protocol to deliver interactive user interfaces, this same mechanism presents significant deserialization vulnerabilities that can be exploited by malicious actors. Durgesh Pawar delves into the intricacies of the CVSS 10.0 "React2Shell" vulnerability, illustrating how manipulation of the Flight protocol can lead to remote code execution. This analysis also offers a practical, ranked set of defenses, ranging from stringent schema validation to enhanced CSRF protection, crucial for fortifying React applications against these inherent structural risks.
React Server Components fundamentally alter the traditional web rendering paradigm. Instead of transmitting HTML or JSON to the browser, they utilize a proprietary streaming protocol known as Flight. This protocol is characterized by its line-delimited format, custom type system, reference resolution mechanisms, and a unique set of rules for reconstructing executable behavior on the client-side. For the majority of React developers, the internal workings of a Flight payload remain an abstraction, handled seamlessly by the framework itself. However, a closer examination reveals a complex system with profound security implications.
The critical security vulnerability, designated CVE-2025-55182 and colloquially termed "React2Shell," emerged in December 2025. This unauthenticated remote code execution vulnerability, boasting a CVSS score of 10.0, was discovered within the Flight deserialization layer. A single, carefully crafted HTTP request to a Server Function endpoint was sufficient for an attacker to gain shell access to a vulnerable system, without requiring any credentials. The severity of this threat was underscored when the U.S. Cybersecurity and Infrastructure Agency (CISA) added it to its Known Exploited Vulnerabilities catalog. Sysdig further linked in-the-wild exploitation to North Korean state-sponsored actors who deployed file-less implants via the Ethereum blockchain, highlighting the sophisticated nature of the attacks.
Investigating the source code, particularly the getOutlinedModel and getChunk functions where the core resolution logic resides, revealed that React2Shell was not an isolated parsing error but rather a symptom of a deeper architectural issue. Flight’s ability to reconstruct executable references, facilitate lazy-loaded components, establish server RPC endpoints, and manage asynchronous state from a stream of text positions it firmly within the domain of deserialization systems. This extends the attack surface far beyond a simple missing hasOwnProperty check, as the protocol itself orchestrates the reconstruction of dynamic behavior. This article will dissect the Flight protocol’s on-the-wire mechanics, identify its deserialization sinks, examine the threats already weaponized by attackers, and outline ongoing risks. It will also present a prioritized list of defenses for securing Server Components, including schema validation for Server Actions, the strategic use of the server-only package, robust CSRF hardening beyond default framework provisions, and an assessment of the Taint API and Web Application Firewalls (WAFs).
Flight On The Wire
To observe Flight in action, one can examine the Network tab in a browser’s developer tools on any Next.js App Router page. Requests returning a Content-Type: text/x-component header indicate a Flight payload. Unlike monolithic JSON responses, Flight is a streaming, line-delimited format, where each line, or "row," is processed by the client-side React runtime as it arrives.
A simplified Flight payload might appear as follows:
1:I["./src/components/ClientComponent.js",["chunks/main.js"],"default"]
2:J["$","article",null,"children":"$1"]
0:D"name":"RootLayout","env":"Server"
Row 1, an import directive, instructs the client to load ClientComponent.js from the bundler’s chunk map. Row 2 constructs an <article> HTML element using a JSON tree, with "$1" serving as a reference to the component imported in chunk 1. Row 0 defines the server execution context, identifying it as a RootLayout operating in a Server environment. This example illustrates the complex interplay of structural data, module references, and inter-chunk pointers that distinguishes Flight from standard JSON.
The Row Format
Each row adheres to the ROW_ID:ROW_TAGPAYLOADn syntax. The ROW_ID is a numeric identifier for cross-referencing, the ROW_TAG is a single character or short string indicating the data type, and the PAYLOAD contains the actual content.
The identified row tags include:
| Tag | Name | Description |
|---|---|---|
| J | JSON Tree | Serialized virtual DOM nodes, component props, and HTML elements. |
| M | Module | Metadata for a specific Client Component module or chunk. |
| I | Import | Instructs the client to load a module from the bundler’s chunk map. |
| HL | Hint/Preload | Directs the browser to preload resources like stylesheets or fonts. |
| D | Data | Server-rendered element context and environment information. |
| E | Error | Serialized server-side exceptions and error boundaries. |
While these tags define a structured data format, the primary attack surface lies within the prefix system.
The $ Prefix System
The $ prefix signals a deviation from literal string interpretation. When encountered by the client-side parser, it triggers a type-specific resolution path managed by the parseModelString function in ReactFlightClient.js. This function acts as a dispatcher based on the character following the $.
| Prefix | Type | Parser Action |
|---|---|---|
$ |
Model Reference | Resolves to another chunk in the stream (e.g., $2 points to row 2). |
$: |
Property Access | Traverses into a resolved chunk’s properties (e.g., $1:user:name). |
$S |
Symbol | Creates a native JavaScript Symbol. |
$F |
Server Reference | Represents a callable Server Action (an RPC endpoint on the server). |
$L |
Lazy Component | Defers component loading until it’s needed in the render tree. |
$@ |
Promise/Raw Chunk | Returns the internal Chunk wrapper object, often acting as a Thenable/Promise, not its resolved value. |
$B |
Blob/Binary | Triggers the blob deserialization handler for binary data. |
Most prefixes resolve a chunk and return its parsed result. The $@ prefix, however, returns the raw internal Chunk object, which React uses to manage resolution state, pending callbacks, and metadata. This object is crucial for Promises and can be exploited to gain a mutable handle. Exposing such internal framework plumbing through the protocol appears to be a significant design oversight.
The $: (property access) prefix is particularly critical. It allows the protocol to specify a path like $1:user:name, instructing the parser to resolve chunk 1, then access .user, and subsequently .name. This represents arbitrary property traversal driven by stream data, a pattern disturbingly similar to prototype pollution vulnerabilities in JavaScript.
This Is Not Just A Data Format
Flight transcends a mere enhanced data format. While JSON provides data, Flight delivers behavior. It reconstructs module references that trigger client-side code execution, establishes callable Server Action endpoints for RPC, sets up Promise chains for asynchronous operations, and creates lazy-loaded component boundaries. Regardless of developer perception, Flight’s mechanics closely mirror deserialization systems that have historically posed significant security risks. The stream dictates not only UI structure but also code loading, function invocation, and trust assignments. The complexity of its chunk resolution path, often challenging to follow statically, necessitates deep dives via debugging and breakpoints. Key files for exploration include react-client/src/ReactFlightClient.js for client-side parsing and react-server/src/ReactFlightServer.js for serialization, with react-server/src/ReactFlightReplyServer.js handling Server Action replies.
Why Flight Is A Deserialization Sink
The dangers of deserialization are well-documented across various languages: Java’s ObjectInputStream leading to ysoserial, Python’s pickle executing code upon load(), PHP’s unserialize chaining magic methods, and .NET’s BinaryFormatter being deprecated. The common thread is the deserialization of attacker-controlled input, leading to the invocation of behavior during reconstruction and ultimately, a loss of execution control.
While JavaScript’s JSON.parse() is inherently safe, producing only plain data objects without constructor invocation or magic methods, this security evaporates when a framework wraps custom deserialization logic around it. Flight exemplifies this, orchestrating the reconstruction of complex structures and behaviors.
Prototype Pollution
JavaScript’s prototype-based inheritance means property lookups traverse the __proto__ chain. An attacker can inject __proto__ or constructor.prototype as keys during reconstruction, thereby modifying base prototypes shared by all objects. This allows for the injection of attacker-controlled values into downstream code that accesses these properties without awareness.
Flight’s $: prefix facilitates property traversal on deserialized objects. The getOutlinedModel function processes colon-separated paths. If these path segments include __proto__ or constructor, the traversal ascends the prototype chain, mirroring the exact mechanism exploited in React2Shell.
Duck Typing and Thenables
The V8 engine and JavaScript specifications treat any object with a .then property as a Thenable. The await keyword checks for this property, invoking it if present without strict type checks. Flight’s asynchronous chunk resolution can be exploited by constructing an object with a manipulated .then property. When the runtime encounters this Thenable during normal await operations, it executes the attacker’s function.
Initially, the $F prefix (Server Reference) seemed the most obvious attack vector. However, deeper analysis revealed the greater potential of $: property traversal. Investigations into chunk status transitions also proved fruitless in finding exploitable states.
The Core Problem
The convergence of these risks in Flight stems from its role as a deserializer of behavior, not just data. The $ prefix system dictates parser control flow: $F creates callable server endpoints, $L enables lazy code loading, $B triggers binary handlers, and $@ exposes internal framework state. An attacker who can influence the stream’s content gains control over which functions the parser invokes, which objects it constructs, and which internal states it exposes.
The Mechanics Of React2Shell
CVE-2025-55182, React2Shell, stands as a stark demonstration of the Flight protocol’s vulnerabilities. This CVSS 10.0 unauthenticated remote code execution flaw in the deserialization layer allowed for complete shell access via a single HTTP request. Understanding its gadget chain reveals the profound power an attacker wielding control over the stream possesses.
The Root Cause
The vulnerability resides in getOutlinedModel, a function responsible for resolving deep property paths via the $: reference system. The exploit chain specifically targeted the server-side reply handling code (ReactFlightReplyServer.js). When parsing a reference like $1:user:name, the function splits the path by colons and iteratively accesses each segment:
for (key = 1; key < reference.length; key++)
parentObject = parentObject[reference[key]];
This concise loop lacks hasOwnProperty checks or validation against prototype chain traversal. Consequently, an attacker could supply a path such as $1:__proto__:constructor:constructor. This path would traverse from a plain JSON object up the prototype chain to the Object constructor, and then to the Function constructor. In JavaScript, the Function constructor can execute arbitrary code, effectively acting like eval(). The absence of allowlists for property names or checks for __proto__ made this exploit possible, with no filtering found in reviveModel or the chunk initialization path.
The Gadget Chain
Transforming the ability to reach the Function constructor into actual RCE requires chaining multiple Flight protocol features. The detailed sequence, as outlined in security analyses, involves a series of steps where legitimate Flight protocol features are exploited in unintended ways. The vulnerability emerges not from a single flawed feature, but from the composition of these features when under attacker control.
Impact
The statistics associated with this vulnerability are alarming:
- CVSS Score: 10.0 (Critical)
- Authentication: None required
- Impact: Remote Code Execution (RCE)
- Affected Component: Flight deserialization layer
- Exploitation Vector: Single HTTP request
What Happened In The Wild
Exploitation was rapid. Sysdig reported that North Korean state-sponsored actors weaponized the vulnerability within hours of its disclosure, deploying the EtherRAT implant. EtherRAT uses the Ethereum blockchain for command-and-control (C2) communication through a technique known as "EtherHiding," making it exceptionally difficult to track and dismantle.
Palo Alto Networks’ Unit 42 documented another threat, a backdoor named KSwapDoor, which masqueraded as a legitimate Linux kernel process. Analysis confirmed KSwapDoor utilized RC4 encryption for internal strings and configuration, with C2 communications secured by AES-256-CFB and Diffie-Hellman key exchange over a P2P mesh network. The swift and sophisticated nature of these campaigns, involving state-sponsored actors deploying novel implants via a single unauthenticated request, underscores the critical need for immediate patching of CVSS 10.0 deserialization vulnerabilities.
The Fix
The React team’s patch for CVE-2025-55182 was direct and effective. The core change involved caching the genuine Object.prototype.hasOwnProperty method at module load time:
var hasOwnProperty = Object.prototype.hasOwnProperty;
Subsequent property checks in the deserialization path utilized .call() with this cached reference:
hasOwnProperty.call(value, i);
This approach effectively blocked prototype chain traversal, even if an attacker attempted to shadow hasOwnProperty on a malicious object. This fix was integrated into React versions 19.0.1, 19.1.2, and 19.2.1.
While the patch successfully neutralizes the known exploit chain, it addresses the symptom rather than the underlying architectural issue. The $: prefix for property traversal remains intact, albeit with validation. The fundamental dynamic persists: the Flight protocol reconstructs behavior from a text stream—executable references, module imports, RPC endpoints, and async state—before application code, validation logic, or authentication middleware execute. Relying solely on framework patches necessitates absolute trust in the discovery and remediation of every deserialization parser edge case. The following defenses offer practical measures to mitigate risks at the application level.
Defenses, Ranked By Impact
These defenses are ranked by their effectiveness in addressing known attack vectors and mitigating potential future threats.

1. Input Validation On Server Actions (Zod, Valibot)
This is the most crucial application-level defense. The Flight deserializer processes raw network input before your application code gains control. Rigorous schema validation serves as the primary barrier against the reconstructed data.
Implement schema validation at the very beginning of every Server Action, preceding any business logic or even logging. Logging untrusted arguments before validation risks exposing source code if a vulnerability like CVE-2025-55183 is triggered.
Libraries like Zod and Valibot are highly effective for this purpose. Validate types, structures, string lengths, numeric bounds, and enumerated values. Reject any input that deviates from the defined schema. Utilize .safeParse() over .parse() to prevent potential leakage of internal error details.
Consider the following example for updating a user profile:
"use server"
import z from "zod"
const UpdateProfileSchema = z.object(
name: z.string().min(1).max(100),
email: z.string().email(),
role: z.enum(["user", "editor"]),
)
export async function updateProfile(formData: FormData)
const parsed = UpdateProfileSchema.safeParse(
name: formData.get("name"),
email: formData.get("email"),
role: formData.get("role"),
)
if (!parsed.success) return error: "Invalid input"
// Proceed with parsed.data; this is the only shape your business logic encounters.
A critical nuance: for Server Actions accepting plain object arguments (not FormData), validate the entire argument before destructuring. Destructuring prior to validation means properties are accessed on unvalidated input, a scenario the Flight deserializer can exploit.
"use server"
import z from "zod"
const CommentSchema = z.object(
postId: z.string().uuid(),
body: z.string().min(1).max(5000),
)
// Recommended: Validate the raw argument first
export async function addComment(data: unknown)
const parsed = CommentSchema.safeParse(data)
if (!parsed.success) return error: "Invalid input"
await db.comments.create(parsed.data)
// Not Recommended: Destructuring before validation
export async function addCommentUnsafe(
postId, body : postId: string; body: string
)
// Properties are accessed on deserialized input before validation.
const parsed = CommentSchema.safeParse( postId, body )
// ...
Server Actions lacking an immediate schema parse are inherently vulnerable. Consider implementing a lint rule to flag use server exports without a validation call as their first statement.
2. The server-only Package
The server-only package provides a straightforward and effective mechanism to enforce code boundaries.
Import server-only at the top of any file containing sensitive information like database credentials, API keys, or proprietary business logic that must never reach the client. If a Client Component attempts to import such a file, directly or indirectly, the build process will fail with a clear error.
import "server-only"
import db from "./database"
export async function getUser(id: string)
return db.query("SELECT * FROM users WHERE id = $1", [id])
Beware of barrel files (index files re-exporting modules). If a barrel file exports both server-only functions and client-safe utilities, importing from that barrel can transitively include the server-only module, leading to build failures or, worse, silently bypassing the protection if the server-only import is not present in the barrel itself. Maintain distinct import paths for server-only and client-safe modules.
Furthermore, server-only does not prevent data leakage through return values. If a Server Component passes sensitive data returned by a server-only function (e.g., user passwords or internal roles) as props to a Client Component, that data will be serialized and transmitted via the Flight stream. server-only protects code boundaries, not data in transit. Explicit filtering of return shapes is essential.
3. CSRF Protections
Following CVE-2026-27978, relying solely on Next.js’s default Origin vs. Host header checks is insufficient. The Origin: null bypass demonstrated edge cases in framework-level CSRF protection.
For state-changing Server Actions (operations involving data writes, deletions, or permission modifications), implement additional layers of protection beyond framework defaults.
Cookie Configuration: Set SameSite=Strict or SameSite=Lax for session cookies. Verify that your session management library (e.g., next-auth or custom solutions) explicitly configures this, as browser defaults can vary.
// next.config.js or your auth configuration
cookies:
sessionToken:
name: "__session",
options:
httpOnly: true,
sameSite: "strict",
secure: process.env.NODE_ENV === "production",
path: "/",
,
,
Explicit CSRF Tokens: For high-value operations (password changes, role assignments, payment processing), generate a per-session CSRF token on the server. Embed this token in a hidden form field or custom header and validate it within the Server Action before proceeding.
"use server"
import cookies from "next/headers"
import validateCsrfToken from "@/lib/csrf"
export async function deleteAccount(formData: FormData)
const token = formData.get("csrf_token") as string
const sessionToken = (await cookies()).get("csrf_secret")?.value
if (!validateCsrfToken(token, sessionToken))
return error: "Invalid request"
// Proceed with deletion.
The allowedOrigins Gotcha: Never include 'null' in experimental.serverActions.allowedOrigins in your Next.js configuration. This literal string matches Origin: null, the header sent by sandboxed iframes, re-opening the CVE-2026-27978 bypass. If legitimate requests trigger CSRF failures, configure your reverse proxy to set correct Origin and Host headers instead of weakening validation.
// Never configure this:
module.exports =
experimental:
serverActions:
allowedOrigins: ["null"], // Reintroduces CSRF bypass vulnerability.
,
,
4. The hasOwnProperty Patch
The React team’s patch for CVE-2025-55182, by caching hasOwnProperty, effectively neutralizes the known RCE gadget chain. Ensuring you are running a patched version is paramount. The fix is available in React 19.0.1, 19.1.2, and 19.2.1. Verify your dependencies:
# npm
npm ls react react-dom react-server-dom-webpack
# pnpm
pnpm ls react react-dom react-server-dom-webpack
# yarn
yarn why react-server-dom-webpack
Versions prior to 19.0.1, 19.1.2, or 19.2.1 are vulnerable to RCE. Update immediately. Furthermore, patches for denial-of-service (DoS) vulnerabilities (CVE-2025-55184, CVE-2025-67779, CVE-2026-23864) require versions 19.0.4+, 19.1.5+, or 19.2.4+. Failure to update may leave your application susceptible to these DoS variants. This patch is reactive, addressing specific exploits rather than fundamentally redesigning the protocol.
5. The Taint API
React’s taintObjectReference and taintUniqueValue functions register sensitive data with the runtime. If tainted data attempts to pass through the Flight serializer, an error is thrown, preventing accidental data leakage to the client.
import
experimental_taintObjectReference as taintObjectReference
from "react"
import "server-only"
export async function getUserRecord(id: string)
const user = await db.users.findUnique( where: id )
taintObjectReference(
"Do not pass the full user object to Client Components. " +
"Select only the fields you need.",
user
)
return user
This API serves as a valuable development-time guardrail, catching honest mistakes like passing entire user objects to client components. However, taint tracking is reference-based and breaks with data derivations:
const user = await getUserRecord(id)
// Taint is lost; spread creates a new object.
<ClientProfile user= ...user />
// Taint is lost; individual properties are not tracked.
<ClientProfile token=user.apiToken />
// Taint is lost; serialization round-trip creates new references.
<ClientProfile user=JSON.parse(JSON.stringify(user)) />
// Taint fires; same object reference.
<ClientProfile user=user />
taintUniqueValue functions similarly for specific strings but also relies on reference tracking. Taint should be viewed as a supplementary development aid, not a primary security boundary.
6. WAFs
Web Application Firewalls can provide an additional detection layer for known attack patterns. They can inspect POST requests carrying the Next-Action header, block payloads containing prototype pollution chains, and flag error responses indicating potential internal data leakage.
Specific WAF rules to consider include:
# Block prototype pollution attempts in request bodies
Rule: body contains "__proto__" OR "constructor:constructor"
Action: BLOCK
Scope: POST requests with header "Next-Action"
# Flag potential Flight error leakage in responses
Rule: response body matches /E{"digest":"[^"]+"/
Action: LOG + ALERT
Scope: responses with Content-Type "text/x-component"
# Block excessively large Server Action payloads
Rule: Content-Length > 1MB for POST with "Next-Action" header
Action: BLOCK (mitigates CVE-2026-23864 zipbomb vector)
However, WAFs can be bypassed through padding or encoding techniques. They are most effective as a noise-reduction layer, catching automated scans and low-effort attacks, rather than as a definitive security boundary against motivated attackers.
What Came After React2Shell
React2Shell was not an isolated incident. Subsequent security audits uncovered a series of related vulnerabilities within the same deserialization surface, though none matched the critical RCE severity of the original.
| CVE | CVSS | Type | Description | Fixed In |
|---|---|---|---|---|
| CVE-2025-55184 | 7.5 | DoS | Infinite recursion of nested Promises in Server Function deserialization. | 19.0.2, 19.1.3, 19.2.2 |
| CVE-2025-67779 | 7.5 | DoS | Incomplete fix for CVE-2025-55184; missed edge cases. | 19.0.4, 19.1.5, 19.2.4 |
| CVE-2026-23864 | 7.5 | DoS/OOM | Unbounded request body buffering and zipbomb-style decompression; memory exhaustion. | 19.0.4+, 19.1.5+, 19.2.4+ |
| CVE-2025-55183 | 5.3 | Info Disc. | Crafted requests reflect Server Function source code during argument stringification. | 19.0.1, 19.1.2, 19.2.1 |
| CVE-2026-27978 | 5.3 | CSRF Bypass | Next.js treated Origin: null (sandboxed iframes) as "missing" instead of "cross-origin." |
Next.js 16.1.7 |
The DoS vulnerabilities highlight the difficulty of patching deserialization parsers, requiring multiple rounds of fixes. CVE-2025-55183 is particularly insidious, enabling source code exposure when Server Functions stringify arguments, potentially revealing sensitive logic and secrets. CVE-2026-27978, a CSRF bypass in Next.js, allowed attackers to invoke Server Actions from sandboxed iframes using a victim’s authenticated session cookies.
What’s Still Exposed
Despite the patches, inherent risks remain within the Flight protocol’s design.
Man-In-The-Middle (MITM) On The Flight Stream
An attacker positioned between the server and client (e.g., through CDN compromise or cache poisoning) could potentially alter the Flight stream in transit. The plain-text, structured format is amenable to manipulation. An attacker could redirect component loading by modifying $I (Import) rows, inject hidden RPC triggers via $F (Server Reference) tags, or alter component props by modifying D (Data) rows. If the target component uses dangerouslySetInnerHTML, this could lead to direct XSS. While Flight escapes $ prefixes in user-supplied strings, this protection is bypassed by a MITM attacker who can write raw protocol commands directly into the stream.
Server Action Enumeration
Server Action IDs, while appearing as obfuscated hashes, are mapped to their source implementations in server-reference-manifest.json. A publicly accessible manifest provides attackers with a complete API map, enabling attacks like IDOR and parameter tampering by forging direct requests with manipulated arguments. Developers often implicitly trust these inputs due to their origin within React’s internal machinery, a misplaced trust with potentially severe architectural consequences.
Encrypted Closure Tampering
When Server Actions capture variables from their scope (closures), Next.js encrypts them using AES with a key stored in NEXT_SERVER_ACTIONS_ENCRYPTION_KEY. While this key typically regenerates with each build, static keys in multi-server environments are vulnerable. An attacker gaining file read access could extract the key, decrypt the closure state, tamper with sensitive parameters (like userId or query parameters), and re-encrypt the data, presenting a forged closure to the server as legitimate.
Supply Chain Activation via Module IDs
Flight references client components by module IDs. A compromised npm package within node_modules, even if not directly imported, could be bundled into a chunk. If an attacker injects $I import references into the Flight stream, the parser might load this dormant module. If the module ID is valid and present in the manifest, there is a theoretical risk of activating malicious code embedded in such dependencies without explicit import in the application’s code.
This Has Happened Before
React Flight is not the first framework to encounter security challenges with custom serialization formats. Google Web Toolkit (GWT) faced similar issues with its RPC protocol, leading to arbitrary deserialization exploits. Java Server Faces (JSF) and ASP.NET serialized ViewState client-side, which, when cryptographic signing was weak or absent, allowed attackers to tamper with serialized state for remote code execution. The recurring pattern involves frameworks creating custom wire formats for rich data transfer, assuming server trust, only to find these formats exploitable through transit manipulation or server-side deserialization of attacker-controlled input. React Flight represents the latest iteration of this persistent security challenge.
Where This Goes Next
The React Flight protocol addresses a complex problem: efficiently streaming interactive component trees from server to client, enabling progressive hydration, asynchronous data loading, and server-driven code splitting. Its functionality is undeniable. However, its security relies on serializing executable references, async state, module pointers, and RPC endpoints over a streaming text protocol, with implicit trust placed in the stream’s structure at both ends. While the React team has diligently patched known vulnerabilities, the underlying design choice of exposing arbitrary property traversal and executable Thenable reconstruction through a network-facing protocol remains a significant concern.
The industry, as more frameworks embrace server-driven UI patterns, will require more robust primitives than the simple notion of "the server is trusted." This necessitates cryptographic validation of serialized payloads, signed component trees, and content integrity checks on the Flight stream itself. The history of deserialization vulnerabilities suggests that relying solely on the parser to handle every edge case is an insufficient long-term strategy. Developers utilizing Server Components are strongly encouraged to thoroughly examine the react-client/src/ReactFlightClient.js code to understand the assumptions their framework makes on their behalf.







