ReactOOPS
ReactOOPS is a Web challenge built with Next.js 16.0.6 and React 19. The package name is react2shell, and the app uses the App Router / React Server Components stack. The intended bug is React2Shell, tracked upstream as <secret redacted>. The provided source...
Scenario
ReactOOPS attack path
ReactOOPS is a Web challenge built with Next.js 16.0.6 and React 19. The package name is react2shell, and the app uses the App Router / React Server Components stack. The intended bug is React2Shell, tracked upstream as . The provided source...
Objective
Challenge walkthrough focused on Web evidence, validation, and reusable operator lessons.
Walkthrough flow
Source and route audit
Trust boundary flaw
Exploit request chain
Admin or proof proof
Source coverage
Moderate source coverage
Status: partial. This article is generated from 4 sanitized Markdown sources and keeps raw flags, credentials, keys, cookies, and reusable secrets out of the rendered blog.
Moderate confidence: the page is useful for review, but it should be treated as partial because the available source material is thinner or less narrative-complete.
- Web/ReactOOPS/writeup.md
- htb-challenge/Web/ReactOOPS/notes.md
- htb-challenge/Web/ReactOOPS/memory-summary.md
- htb-challenge/Web/ReactOOPS/hypothesis-board.md
Technical Walkthrough
ReactOOPS - Writeup
Summary
ReactOOPS is a Web challenge built with Next.js 16.0.6 and React 19. The package name is react2shell, and the app uses the App Router / React Server Components stack. The intended bug is React2Shell, tracked upstream as <secret redacted>.
Analysis
The provided source has no custom input handling, API routes, middleware, or user-defined server actions. The Dockerfile copies the flag to /app/flag.txt and runs the standalone Next.js server.
The live response exposes RSC/App Router behavior via headers such as Vary: rsc, next-router-state-tree and embedded flight data. Next.js 16.0.6 is in the vulnerable range; fixed versions include 16.0.7.
Exploit
The exploit sends a crafted multipart/form-data request with a fake React Flight chunk. The payload walks prototype references to obtain the Function constructor, then uses the $B blob handler gadget to execute JavaScript in the Node.js process.
The command copies /app/flag.txt over an existing served static chunk. Requesting that chunk then returns the flag.
python3 solve/exploit.py http://<TARGET>:32509/Result
The flag was captured and saved to loot/flag.txt.
Source-Backed Dossier
The sections below are merged from companion Markdown notes for the same case. They are rendered after sanitization so the article stays precise without publishing raw flags, credentials, or target-specific secrets.
Notes
Scope
- Challenge: ReactOOPS
- Category: Web
- Difficulty: Very Easy
- Target:
http://<TARGET>:32509/ - Workspace:
<local workspace>
File Inventory
files/web_reactoops/challenge/package.json: Next.js16.0.6, React^19, package namereact2shell.files/web_reactoops/challenge/app/page.tsx: static page; no user routes, API routes, or server actions.files/web_reactoops/Dockerfile: copies challenge flag to/app/flag.txt; runs standalone Next server on port1337.
Evidence Ledger
| Timestamp | Action | Output File | Finding | Next Step |
|---|---|---|---|---|
| 2026-05-07 | Reviewed package/source | files/web_reactoops/challenge/package.json | Next.js 16.0.6 + React 19 + react2shell naming points to React2Shell | Validate against live instance |
| 2026-05-07 | Fetched / | analysis/index-response.txt | RSC/App Router headers and flight data present | Research matching CVE |
| 2026-05-07 | Researched React2Shell | Web sources | <secret redacted> affects React 19 RSC and Next.js 16.0.6; exploit uses multipart Server Action request | Build payload |
| 2026-05-07 | Sent crafted multipart request | terminal output | React2Shell RCE executed; newly-created static files were not served | Use existing chunk as readback channel |
| 2026-05-07 | Overwrote existing static chunk with /app/flag.txt | solve/exploit.py | Existing _next/static/chunks/*.js route returned flag content | Save flag |
| 2026-05-07 | Verified flag format | loot/flag.txt | <flag stored in loot/flag.txt> flag captured | Write reproducible solution |
| 2026-05-07 | Rechecked target after capture | terminal output | Remote instance at <TARGET>:32509 no longer accepted connections | Keep local solve and loot as final evidence |
Key Insight
There is no application-specific bug in the page source. The vulnerable surface is the framework itself: React Server Components deserialization in React 19 / Next.js 16.0.6.
The practical readback channel was to copy /app/flag.txt over an already-served Next.js static chunk, then request that chunk path.
Sources Used
- Next.js GitHub advisory:
https://github.com/vercel/next.js/security/advisories/GHSA-9qr9-h5gf-34mp - Next.js CVE page:
https://nextjs.org/blog/<secret redacted> - Public React2Shell exploit analysis mirrored by Sploitus:
https://sploitus.com/exploit?id=160CB49F-3A19-5F23-<secret redacted> - Miggo technical breakdown:
https://www.miggo.io/post/react2shell-cve-2025-55182-technical-breakdown
| 2026-05-27T23:35:18Z | backfill | challenge-state.json | Legacy workspace backfilled with deterministic state | High | Validate before further work |
Memory Summary
Metadata
- Platform: HackTheBox Challenges
- Category:
- Challenge:
- Difficulty:
- Source workspace:
Validated Solve Chain
Concepts only. Do not include raw flags, reusable credentials, tokens, cookies, private keys, or live secrets.
1.
Reusable Lessons
-
Dead Ends
-
Tool Quirks
-
Evidence Paths
-
Ingestion Decision
- Proposed for LightRAG: yes/no
- Requires user approval before ingestion: yes
Hypothesis Board
| Rank | Path | Evidence | Missing Proof | Cheapest Validation | Confidence | Status |
|---|
Closed Branches
| Branch | Evidence Tested | Failure Output | Reason Closed | Revisit Condition |
|---|
Technical analogy
How to remember this solve
Think of the web app like a building with signs on every door. The solve usually comes from reading the map carefully, finding the door the app forgot to hide, then sending the exact request that proves you understand the route.
For ReactOOPS, keep the mental model simple: identify the trusted assumption, prove it with the smallest safe test, then automate or repeat only the part that directly leads to the flag.