News Froggy
newsfroggy
HomeTechReviewProgrammingGamesHow ToAboutContacts
newsfroggy

Your daily source for the latest technology news, startup insights, and innovation trends.

More

  • About Us
  • Contact
  • Privacy Policy
  • Terms of Service

Categories

  • Tech
  • Review
  • Programming
  • Games
  • How To

© 2026 News Froggy. All rights reserved.

TwitterFacebook
Programming

React2Shell: Unpacking a Critical RCE in React Flight

React2Shell (CVE-2025-55182) was a critical RCE vulnerability in React's Flight protocol, discovered by unpicking its undocumented internal workings. It leveraged how Flight deserializes complex objects and how `await` leniently handles "thenables," ultimately allowing attackers to execute arbitrary code by manipulating React's internal promise resolution logic.

PublishedMay 9, 2026
Reading Time6 min

In late 2025, a critical remote code execution (RCE) vulnerability, dubbed "React2Shell" (CVE-2025-55182), shook the React ecosystem. This discovery, initially a deep dive into an undocumented protocol, revealed fundamental flaws affecting millions of websites. This post recounts the technical journey, from unraveling an obscure communication format to uncovering how an oversight in handling asynchronous operations could lead to arbitrary code execution.

The Mystery of React Flight

Modern React frameworks like Next.js extensively use React Server Components (RSC) for efficient server-side rendering and React Server Functions (formerly Server Actions) to enable seamless invocation of server-side JavaScript from client-side code. To facilitate these advanced features, React introduced a novel communication protocol for exchanging complex JavaScript objects between the browser and server. This protocol, known as "Flight," handles data types beyond what standard JSON can represent, such as Date, BigInt, Map, circular references, and Promises.

Initially, Flight's details were scarce, with no formal specification and limited documentation. Developers often mistook its requests, which look like URL-encoded JSON with special markers, for standard JSON. An example of a Flight message might look like this:

0 = { "email": "test@example.com", "updated": "$D04 Dec 1995 00:12:00 GMT", "details": "$1" } &1 = { "firstName": "$2", "lastName": "$3:foo" } &2 = "John" &3 = { "foo": "Doe" }

Once parsed, this resolves to a rich JavaScript object on the server:

javascript { "email": "test@example.com", "updated": Date(Mon Dec 04 1995 13:12:00 GMT+1300 (New Zealand Daylight Time)), "details": { "firstName": "John", "lastName": "Doe" } }

The $ syntax in Flight denotes special types: $D for a Date object, $x for a reference to another chunk, and $x:y for property selection. This ability to reference properties, including those inherited from a prototype, became a critical early observation. For instance, sending { "foo": "$1:toString" } with &1=123 would successfully retrieve Number.prototype.toString and place it on the attacker's object. While seemingly benign due to adhering to standard JavaScript prototype lookup, this was later recognized as a "glaring omission of a safety check."

Initial Exploitation Avenues and Type Safety Illusions

Initially, the hunt wasn't for a vulnerability in Flight, but for ways to abuse Flight in Next.js applications that lacked proper input validation. Flight's ability to send complex objects meant developers' assumptions about user input types could be easily broken. Consider a server function:

javascript async function sayHello(name: string): string { 'use server' return 'Hello, ' + name + '!' }

Despite the name: string type annotation, TypeScript only provides build-time type checking. At runtime, an attacker could send a custom object. If this object had a malicious function on its toString property, concatenation with 'Hello, ' would implicitly invoke it. Similarly, a function like str.replaceAll(before, after) could be exploited if str were an attacker-controlled object with a custom replaceAll method.

These examples highlight the "illusion of type safety." TypeScript types are compile-time aids, not runtime guarantees, making runtime validation of untrusted input crucial, especially when dealing with protocols that allow arbitrary object construction.

The Breakthrough: Abusing Thenables

The real breakthrough came when examining how React's await decodeReply(...) function processed incoming Flight payloads. This function is designed to handle JavaScript Promises, but it also leniently processes "thenables" – any object with a .then method. await invokes Promise.resolve, which, if it encounters a thenable, will call its .then method with resolve and reject callbacks as arguments. Crucially, if a thenable resolves to another thenable, it too is automatically awaited and invoked.

This behavior opened a significant attack vector. An attacker could send a Flight payload like { then: Array.prototype.push }. When await decodeReply(...) processed this, it would call Array.prototype.push on the attacker's object, passing React's internal resolve and reject functions as arguments. This effectively allowed an attacker to call an arbitrary function on their object, with React's internal promise resolution functions as arguments. While this initially seemed like just another way to call an attacker-controlled function, its true power lay in the ability to chain calls and manipulate internal execution flow.

Accessing React's Internals and the Path to RCE

The final piece of the puzzle involved leveraging Flight's internal mechanisms. Flight uses $@x to create a Promise of a chunk that will arrive later, which internally constructs a new Chunk(...) object. This Chunk object inherits from Promise and contains React's internal .then implementation.

By crafting a Flight payload that references Chunk.prototype.then and applies it to an attacker-controlled object, the RCE became tangible. Specifically, a payload like 0 = { "then": "$1:then" } &1 = "$@2" would cause React's Chunk.prototype.then to be invoked against the attacker's object. React's internal then implementation, expecting a Chunk object, would attempt to access properties like .status and .reason on the attacker's malicious object. Since these properties would be undefined or attacker-controlled, this interaction allowed the attacker to effectively spoof internal Chunk state and manipulate React's core logic.

The immediate implication was the ability to trick React into believing it was dealing with valid internal constructs, leading to a path where an attacker could influence the "server manifest" – the strict list mapping Server Function IDs to actual server-side code. By corrupting or controlling this manifest, an attacker could potentially invoke arbitrary functions, achieving remote code execution.

Practical Takeaways

The React2Shell vulnerability serves as a stark reminder of several critical security principles for developers:

  1. Validate All Untrusted Input: Never rely solely on compile-time type annotations (like TypeScript) for runtime safety. Always perform robust runtime validation of data received from clients, especially when dealing with complex data structures or novel communication protocols.
  2. Understand Underlying Protocols: Abstracted frameworks can hide complex underlying mechanisms. A deeper understanding of how data is serialized, transmitted, and deserialized (like with Flight) can reveal unexpected attack surfaces.
  3. Beware of Implicit Conversions and Asynchronous Magic: JavaScript's flexible nature, including implicit type coercion and the lenient handling of thenables by async/await, can create subtle security vulnerabilities. Be explicit with types and conversions wherever possible.
  4. Security in Depth: Even battle-tested frameworks can have critical vulnerabilities. A multi-layered security approach, including robust input validation, secure coding practices, and regular security audits, is essential.

FAQ

Q: What is the primary difference between Flight and standard JSON?

A: Flight extends JSON's capabilities by supporting complex JavaScript types (like Date, BigInt, Map, Promise), references (including circular ones), and even server-side function references, which JSON cannot natively represent.

Q: How does TypeScript's type safety relate to the React2Shell vulnerability?

A: TypeScript provides build-time type checking, which helps catch errors during development. However, it does not enforce types at runtime. The vulnerability exploited this by sending arbitrary objects from the client, bypassing the server-side code's expectation of a specific type (e.g., string), even if that type was declared in TypeScript.

Q: What is a "thenable" and why was its behavior crucial for React2Shell?

A: A thenable is any JavaScript object that has a .then method. The await keyword, when used with Promise.resolve, leniently invokes this .then method. This behavior was crucial because it allowed attackers to force React's internal resolve and reject functions to be passed as arguments to an attacker-controlled .then method on a malicious object, effectively manipulating React's internal asynchronous execution flow.

#React#Next.js#Security#Vulnerability#JavaScript

Related articles

Build Your Own Local NMT App with React Native and QVAC
Programming
freeCodeCampJul 18

Build Your Own Local NMT App with React Native and QVAC

This article explores how Neural Machine Translation (NMT), powered by the Transformer architecture, revolutionized translation by understanding context. We then delve into QVAC, a local-first AI development platform, and its Bergamot engine, enabling private, on-device translation. Learn to set up a React Native app with QVAC and manage model lifecycles for efficient local translation.

ASML Low-NA EUV Pricing: Value Capture or Cost Burden
Review
Tom's HardwareJul 18

ASML Low-NA EUV Pricing: Value Capture or Cost Burden

The Industry Reacts: ASML's EUV Pricing Shift Verdict: ASML’s strategic move to broaden its value-based pricing for Low-NA EUV tools, looking beyond mere wafer throughput, marks a significant shift in the semiconductor

Unpacking Roman Concrete's Durability: Carbonation and Self-Healing
Programming
Hacker NewsJul 17

Unpacking Roman Concrete's Durability: Carbonation and Self-Healing

The Enduring Legacy: Roman Concrete's Millennia-Long Stand As software developers, we're familiar with the ephemeral nature of technology; systems evolve, frameworks deprecate, and codebases undergo constant

PayPal in Microservices: NestJS, gRPC, and Docker Blueprint
Programming
freeCodeCampJul 17

PayPal in Microservices: NestJS, gRPC, and Docker Blueprint

Integrating payment logic directly into every microservice within a distributed system often leads to significant challenges. Scattering PayPal API calls across services like user-service, order-service, or

Demystifying Dijkstra's Algorithm: The Shortest Path Pioneer
Programming
freeCodeCampJul 16

Demystifying Dijkstra's Algorithm: The Shortest Path Pioneer

Explore Dijkstra's Algorithm, the foundational pathfinding technique conceived by Edsger W. Dijkstra. This guide explains how it solves shortest path problems using graphs, nodes, edges, and weights. Learn its greedy approach and the critical role of data structures like adjacency lists and priority queues in its efficient Python implementation.

AWS Leadership Shift: What It Means for Compute and AI/ML
Programming
GeekWireJul 16

AWS Leadership Shift: What It Means for Compute and AI/ML

Dave Brown, a key figure in AWS's EC2 and AI/ML growth, is departing. His successor, Dave Treadwell, brings extensive experience from Microsoft and Amazon's eCommerce Foundation, potentially signaling new directions for core cloud services and AI innovation.

Back to Newsroom

Stay ahead of the curve

Get the latest technology insights delivered to your inbox every morning.