The $25,000 Bug: Explaining the React2shell Vulnerability

react2shell vulnerability

“React2Shell” is the name for the critical vulnerability CVE-2025-55182, which allows unauthenticated Remote Code Execution (RCE) in React Server Components (RSC) due to an unsafe deserialization flaw.

Numerous public proof-of-concept (PoC) exploits are available on platforms like GitHub and are actively being used by attackers in the wild.

Understanding Vulnerability

The React2Shell vulnerability comes from improper handling of the React “Flight” protocol, the serialization format used to transfer data between the client and server in RSC.

  1. Unsafe Deserialization: The core issue is an insecure deserialization flaw (CWE-502) where the server reconstructs objects from a text stream without sufficient validation.
  2. Prototype Pollution: This flaw allows an attacker to manipulate the JavaScript prototype chain (CWE-1321), ultimately tricking the server into executing malicious code using the JavaScript Function constructor.
  3. Impact: The vulnerability has a maximum CVSS score of 10.0 and affects many popular frameworks that use RSC, including Next.js (which has its own corresponding CVE-2025-66478, though it is considered a duplicate of the original).

Publicly Available PoCs

Several security researchers, including the original discoverer Lachlan Davidson, have published working PoC exploits to demonstrate the vulnerability. These are widely circulating online.

  1. Original Researcher PoC: The original PoCs submitted to Meta are available on GitHub, providing technical insight into the exploitation mechanism.
  2. Detection Scanners: Tools like the one by Assetnote provide a safe way to check if a system is vulnerable using specific detection patterns without causing harm.
  3. Active Exploitation Tools: Some public repositories offer functional, interactive RCE shells for authorized testing and research.

Mitigation and Defense

Public PoCs accelerate the timeline for mass exploitation, making immediate patching essential. The only robust fix is to upgrade to a patched version of React.

Affected Versions:

  • React versions 19.0, 19.1.0, 19.1.1, and 19.2.0 are vulnerable across react-server-dom-webpackreact-server-dom-parcel, and react-server-dom-turbopack.

Fixed Versions:

  • React Server Components: Upgrade to versions 19.0.119.1.219.2.1 or later.
  • Next.js: Upgrade to patched versions, such as 15.0.515.1.916.0.7 or later, depending on your release line.

How to find React2Shell vulnerability

The safest and recommended way to check for the React2Shell vulnerability (CVE-2025-55182) is to use a dedicated vulnerability scanner or check the application’s source code and dependencies.

Method 1: Using an Automated Scanner

Security researchers have developed reliable tools that check for vulnerabilities using non-intrusive methods. The most widely recommended is the open-source scanner from Assetnote.

  1. Download the scanner: Obtain the scanner tool from the official Assetnote GitHub repository.
  2. Run the scan: The scanner sends a specifically crafted, but harmless, HTTP POST request to your application’s server component endpoints. It uses a “safe-check” mode by default, which relies on a side-channel indicator (a specific error condition or response header) rather than attempting actual code execution.
  3. Analyze the results: If your host returns a 500 status code with E{"digest" in the response body, or a specific value in the X-Action-Redirect header, it is likely vulnerable. Other responses usually indicate the application is not running the affected component in a vulnerable configuration.

Method 2: Manual Code and Dependency Check

You can directly inspect the application’s build configuration to determine exposure.

  1. Check for Server Components: Look in your application’s source code for the "use server"; directive, which signifies that React Server Functions are being used.
  2. Verify Framework: Confirm if you are using Next.js with the App Router enabled, as this configuration is vulnerable by default. The presence of an app directory often indicates the App Router is in use.
  3. Inspect Dependencies: Check your package.json or equivalent dependency management files for the presence and version numbers of the react-server-dom-webpackreact-server-dom-parcel, or react-server-dom-turbopack packages.
  4. Identify Affected Versions: Your website is vulnerable if it uses any of these packages in versions: 19.0.0 through 19.0.119.1.0 through 19.1.1, and 19.2.0

Vulnerability Detection Technique

You can safely detect the React2Shell vulnerability using a dedicated “safe-check” method that verifies the presence of the vulnerability without executing any malicious commands. This method relies on triggering a specific, non-exploitative error condition.

The safest way to verify the vulnerability is by sending a benign payload that causes a specific error response only in vulnerable versions of React Server Components (RSC). The server will crash gracefully in a detectable manner, but no code is executed.

Here is how to adapt the Python code for a safe, non-exploitative check:

This script uses a simple payload that interacts with an empty object, triggering a unique crash behavior in vulnerable servers (a 500 status code with a specific digest in the response body).

import requests
import json

# --- Configuration ---
# Target URL - typically a Next.js API route or RSC endpoint
TARGET_URL = "target-website.com"
# ---------------------

# The safe detection payload
# This payload triggers a specific crash indicator without executing arbitrary code.
safe_payload = [
    {"__proto__": None},
    None,
    None,
    None,
    None,
    None,
    0,
    None,
    {"$1:a:a": 1} 
]

headers = {
    'Content-Type': 'text/x-component; charset=utf-8',
    'Accept': 'text/x-component; charset=utf-8',
    'User-Agent': 'Mozilla/5.0 (safe-check-scanner)'
}

print(f"Sending safe detection request to {TARGET_URL}")

try:
    response = requests.post(TARGET_URL, data=json.dumps(safe_payload), headers=headers, timeout=10)
    print(f"Request sent. Status Code: {response.status_code}")
    print(f"Response Body snippet: {response.text[:100]}...")

    # Check for the specific vulnerability indicator
    if response.status_code == 500 and 'E{"digest"' in response.text:
        print("\n✅ **VULNERABLE:** The server returned the expected crash indicator.")
        print("Your system is highly likely vulnerable to CVE-2025-55182.")
    else:
        print("\n❌ **NOT VULNERABLE (via safe check):** The server did not return the specific crash indicator.")
        print("The system might be patched, mitigated, or the endpoint is incorrect.")

except requests.exceptions.RequestException as e:
    print(f"\nAn error occurred during the request: {e}")

Save the script above as a Python file for example safe_check.py

Ensure Python and the requests libraries are installed with the following command:

pip install requests

Change the TARGET_URL variable to your website’s relevant endpoint.

Run the script from your terminal:

python safe_check.py

Security firm Assetnote, whose method this is based on, provides a professionally maintained open-source scanner tool on GitHub that uses this exact safe mechanism by default. Using this dedicated tool is generally more robust than a simple script.

Remediate React2Shell

To properly detect the React2Shell vulnerability, you must use the specific method mentioned previously:

Use a tool like the Assetnote scanner that sends a specific, non-harmful payload that triggers a unique error code (500 status with E{“digest” in the response body) only in vulnerable systems.

If your system is vulnerable, the only fix is to update your React and Next.js packages to the patched versions:

React Server Components: Upgrade to versions 19.0.119.1.219.2.1 or later.

Next.js: Upgrade to patched versions, such as 15.0.515.1.916.0.7 or later.

If you find this write-up useful, look at our guide on the model context protocol, which helps AI systems securely access tools, APIs, files, and memory.

Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Post
Model context protocol

What Is Model Context Protocol? All You Need To Know