Developing a Custom Nmap NSE Script to Detect React2Shell (CVE-2025-55182) React2Shell (CVE-2025-55182) represents a critical flaw in the React Flight protocol's deserialization logic, specifically affecting React 19.0.0 through 19.2.0 and downstream frameworks like Next.js. The vulnerability allows unauthenticated attackers to achieve Remote Code Execution (RCE) by sending crafted serialized objects to React Server Component (RSC) endpoints. Unlike traditional web vulnerabilities that target application logic, React2Shell exploits the internal communication channel used to sync server-side state with the client-side UI, making any application using the App Router or RSC potentially vulnerable out of the box.

Analyzing the Flight Protocol Attack Surface

The Flight protocol is the backbone of React Server Components. When a client interacts with an RSC-enabled application, the browser sends a POST request to the server, often identified by headers like Next-Action or RSC: 1. The server then processes a serialized payload, executes the requested server function, and returns a stream of UI components. The core of CVE-2025-55182 lies in the react-server-dom-webpack (and similar bundler-specific) packages, which fail to validate the structure of incoming serialized component trees.

Attackers exploit this by injecting malicious objects into the stream. Because the server-side decoder trusts these objects during reconstruction, it can be coerced into prototype pollution or direct object injection that leads to the execution of arbitrary JavaScript within the Node.js runtime. Identifying these endpoints during an engagement requires more than just a standard port scan; you need to find the specific API routes that handle these Flight requests, which are often obscured or dynamically generated.

Discovery and Reconnaissance at Scale

Before deploying a detection script, you need a high-fidelity list of targets. Standard fingerprinting often misses React 19 instances because they present as generic Node.js or Next.js applications. Using a tool like Zondex allows for internet-wide reconnaissance to identify specific headers and technology stacks that correlate with vulnerable React versions. Specifically, looking for x-nextjs-cache or the presence of /_next/data/ in response bodies can narrow down the search to modern Next.js deployments.

Once targets are identified, we can verify the specific React version by inspecting the _next/static/chunks/ directory or checking for the react-server-dom-webpack manifest. On a targeted network, a basic Nmap scan with service detection is the starting point:

nmap -sV -p 80,443,3000,8080 --script http-methods <target-ip>

Building the Custom NSE Script

A custom Nmap Scripting Engine (NSE) script provides a lightweight, scalable way to probe for React2Shell without the overhead of a full vulnerability scanner. Our script will target the action endpoints commonly used by React 19. The detection logic involves sending a non-destructive, malformed serialized object to the server and monitoring for a specific 500 error or a "Prototype Polluted" state if a safe payload is used.

NSE Script Architecture

The script requires the http, shortport, and stdnse libraries. We define the portrule to target common HTTP ports and the action function to handle the exploitation logic. The payload must mimic the structure of a serialized Flight protocol request, which uses a specific line-delimited format (e.g., 1:{"id":"..."}).

local http = require "http"
local shortport = require "shortport"
local stdnse = require "stdnse"

description = [[
Detects the React2Shell (CVE-2025-55182) vulnerability in React Server Components.
Attempts to identify unauthenticated RCE/Prototype Pollution in the Flight protocol.
]]

author = "PentestFieldNotes"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"vuln", "intrusive"}

portrule = shortport.http

action = function(host, port)
    local target_path = "/api/functions" -- Common RSC endpoint
    local payload = "0:[\"$L1\"]\n1:{\"__proto__\":{\"vulnerable\":\"React2Shell\"}}"
    
    local options = {
        header = {
            ["Content-Type"] = "text/x-component",
            ["RSC"] = "1",
            ["Next-Action"] = "d9f8c7b6" -- Placeholder Action ID
        }
    }

    local response = http.post(host, port, target_path, options, nil, payload)

    if response and response.status == 200 then
        -- Check if the server accepted the payload or returned a specific error
        if response.body:match("vulnerable") then
            return stdnse.format_output(true, "VULNERABLE: React2Shell (CVE-2025-55182) detected via Prototype Pollution.")
        end
    elseif response and response.status == 500 then
        -- Some patched versions or specific WAFs will drop the connection or 500
        stdnse.debug1("Received 500, could be a crash or a partial patch.")
    end

    return nil
end

Developing the Detection Payload

The payload variable in the script is the most critical component. In a real-world exploit, this would be a serialized function or object that hooks into the server-side rendering logic. For a safe detection script, we target the __proto__ object. If the server is vulnerable to the insecure deserialization aspect of React2Shell, it will attempt to merge our object into the global prototype, which we can then verify in the response if the server-side code reflects any part of the state back to the client.

In many Next.js environments, the endpoint isn't always /api/functions. Attackers often need to fuzz for the valid Next-Action ID, which is a hash found in the client-side JavaScript bundles. While our NSE script uses a placeholder, a more robust implementation would first perform a GET request to the homepage to scrape for valid action IDs before attempting the POST probe.

Execution and Verification

To run the script, save it as react2shell-check.nse in your Nmap scripts directory (usually /usr/share/nmap/scripts/) and update the Nmap database. Running this against a target range is straightforward:

nmap --script-updatedb
nmap -p 443 --script react2shell-check.nse --script-args="path=/action-route" <target-range>

For more comprehensive validation, particularly when dealing with complex WAF bypasses, tools like Secably can be used to run automated web security tests that include deeper context-aware payload variations. This is useful for confirming if a 500 error is a legitimate vulnerability or just a generic application error.

Handling Response Variations

Expect different behavior depending on the bundler (Webpack vs. Turbopack). A successful probe might return a text/x-component stream containing the injected property. If the system is patched (React 19.2.1+), the server will either ignore the malformed payload or throw a Digest error that does not leak internal state. Monitoring these nuances in the Nmap output using -d or --script-trace is essential for debugging the detection logic.

# Example of tracing the script to see raw HTTP exchanges
nmap -p 8080 --script react2shell-check.nse --script-trace <target>

Detection and Remediation Logic

When the script identifies a vulnerable host, the primary remediation is an immediate upgrade to React 19.2.1 or higher. If upgrading the entire framework is not feasible, developers should apply the "Flight validation" middleware that explicitly filters any incoming request with the text/x-component content type that contains suspicious keys like __proto__ or constructor.

From a scanning perspective, it is also worth checking for environment-specific bypasses. If the target is behind a proxy, using GProxy can help rotate IP addresses during the discovery phase to avoid triggering rate limits on the sensitive RSC endpoints. This ensures that the detection script has a clear path to the backend without being throttled by front-end security layers.

Refining the Detection Route

If the target application uses a custom base path or a specific sub-domain for its API, you must modify the target_path variable. Modern Next.js apps often use /_next/data/<build-id>/... for client-side navigation data, which also utilizes the Flight protocol and can be a secondary vector for React2Shell. Expanding the NSE script to iterate through these paths based on the build-id scraped from the source code increases the detection surface significantly.