Before reading this, please make sure you understand the basics of JavaScript. This article is a continuation of something I created earlier, so it helps to be familiar with that first: https://medium.com/@anandhukannan/javascripts-dna-3fb35f2106a6

What Is React Flight Protocol?

In modern React (Server Components), the server doesn't send full HTML only.

It sends a serialized data stream that describes:

  • Components
  • Props
  • References to other objects

This format is called the Flight protocol.

A compressed instruction language React uses to rebuild UI on the client.

Instead of sending full objects, it sends references like:

1. Flight Protocol Really

Forget React for a second.

Imagine the server wants to send this object to the client:

const user = {
  name: "Anandhu",
  profile: {
    email: "anand@example.com"
  }
};

Instead of sending the whole object every time, it sends:

"$1:name"
"$1:profile:email"

This is just a string path.

That string literally means:

obj["profile"]["email"]
So it is basically:
object[property1][property2][property3]

So Flight protocol is basically:

A string that tells JavaScript how to walk through an object.

2. What The Vulnerable Code Is Actually Doing

The client is NOT sending the full object.

It sends a reference string.

Instead of sending:

{
  "profile": {
    "email": "anandhu@example.com"
  }
}

It sends something like:

"$1:profile:email"

That string is basically:

Take object #1 Go to profile Go to email Return value

The server already has the full object in memory.

The client only sends instructions.

Why Send Only Directions?

Because React Server Components work like this:

  1. Server builds components
  2. Server stores them in a map (chunks)
  3. Client receives references
  4. Client sends back references for actions

It's like saying:

"Hey server, remember that object you created earlier? Give me this specific part of it."

So no need to resend entire object every time.

That's why it looks like "no data" is being sent.

The real data is already on the server.

3. The Problem

In vuln React2Shell, the server code similar like this:

None

The server code does NOT check: obj.hasOwnProperty(path[i])

It just trusts: obj[path[i]]

Remember what we learned earlier:

If a property doesn't exist, JavaScript looks at the prototype.

That's the problem.

What Happens With "proto"

If attacker sends:

"$1:__proto__"

Then the loop does:

obj = obj["__proto__"];

That moves from:

Object → Object.prototype

Now attacker is no longer inside normal object.

They are inside the prototype.

And that prototype contains powerful things like:

  • constructor
  • toString
  • valueOf

Why constructor Is Dangerous

Earlier we learned:

obj.constructor === Object
Object.constructor === Function
So: obj.constructor.constructor === Function
And
Function("console.log('hi')")()

Executes code.

So if attacker can reach:

__proto__ → constructor → constructor

They reach: Function ,That's the entire core of the RCE.

4. React2Shell vuln

React2Shell exploits how React Server Components resolve references sent from the client.

The vulnerable logic looks conceptually like this:

obj = obj[path[i]];

If the attacker controls path, they control what the server accesses.

What Do They Target?

They target:

1. The React Server Reference Resolver

In React Flight (Server Components), the server keeps internal objects like:

  • Module references
  • Server action handlers
  • Built-in Node modules

When the client sends a Flight payload, React resolves references like:

$1:some.module:property

The server then walks object properties dynamically.

This is where traversal happens.

They Try to Reach Dangerous Objects

The goal is not just { a: { b: 10 } }.

The goal is to reach something like:

  • global
  • process
  • process.mainModule
  • require
  • child_process
  • or something that leads to code execution

For example (conceptually):

global.process.mainModule.require("child_process").exec("whoami")

If the traversal logic allows walking through these objects without restriction…

In Simple Words

React2Shell targets:

The server's object traversal logic that resolves module references from client-supplied paths.

Because if the client can control the traversal path, they can escape the intended object, reach Node internals, and execute system commands.

Think of It Like This

Attacker version:

let obj = global;
let path = ["process", "mainModule", "require", "child_process", "exec"];

If that traversal is allowed:

RCE.

None