React's Server is Shockingly Fragile

Two new React vulnerabilities can crash your server or leak your code with a single, simple request. The fixes for last week's critical flaw won't protect you from this.

industry insights
Hero image for: React's Server is Shockingly Fragile

React's Fragile Peace Is Shattered. Again.

React’s uneasy truce with server-side security just exploded. Days after a critical Remote Code Execution (RCE) bug in React Server Components, two more high‑impact flaws landed: a full Denial of Service (DoS) and a server action source code leak. Both hit the exact same experimental surface area—React’s new server-side architecture and the React Flight protocol.

These are not esoteric, chain‑four‑bugs‑together exploits. A single, unauthenticated HTTP POST request can stall your app or dump server action code back to the client. Better Stack’s “React Got Hacked, Again” demo shows a stock Next.js 16.0.8 app, with zero custom server actions, knocked offline by one crafted request.

The DoS vulnerability abuses how React Flight deserializes chunked data. By wiring chunk 0 → chunk 1 and chunk 1 → chunk 0, the server falls into an infinite resolution loop, pegs CPU, and stops serving even basic GET requests. CVE-2025-55184 and CVE-2025-67779 score 7.5 (High), and they affect the same RSC plumbing that shipped in React 19.0.0–19.2.0.

Right behind it, CVE-2025-55183 exposes server action source code with another trivial POST. By tricking the deserializer into passing a server function reference as its own argument, React ends up stringifying the function and returning its implementation in the HTTP response. The CVSS 5.3 rating understates the risk if that code embeds business logic or mishandled secrets.

Most alarming: the earlier RCE patch from December 3 does nothing against these two bugs. If you stopped at “React Got Hacked, Again” One and only applied that fix, your app still sits open to a one‑packet DoS and code exposure. The React team’s own React Blog post says it plainly: Upgrade immediately.

Scrutiny around React’s server era is now intense. React Server Components, Server Actions, and the React Flight protocol promise a Radically better DX, but three CVEs in under two weeks raise hard questions. Libraries and frameworks built on this stack—Next.js, React Router, Waku, Redwood, custom RSC plugins—must treat these as ecosystem‑level incidents, not isolated bugs.

One POST Request to Crash Everything

Illustration: One POST Request to Crash Everything
Illustration: One POST Request to Crash Everything

One malformed HTTP request can quietly suffocate a React server. Security researchers disclosed a high‑severity DoS flaw (CVSS 7.5) in React Server Components that lets any unauthenticated client hang a process indefinitely. Under load, a few such requests can pin CPU cores at 100% and make an entire deployment unresponsive.

At the center of the bug sits the React Flight protocol, the wire format React uses to stream component trees and server actions as “chunks.” Each chunk can reference another chunk using a dollar-sign notation like `"$1"`, which tells the deserializer to “go fetch chunk 1 and keep resolving until you have a final value.” On a healthy server, this chain eventually lands on a concrete object or primitive.

Attackers instead send a POST body that never resolves. By crafting a cyclic graph—chunk `0` points to chunk `1`, and chunk `1` points straight back to chunk `0`—they weaponize the deserializer’s trust in those references. No exotic tooling required: a single POST with hostile JSON or multipart data aimed at a Server Functions endpoint can trigger the loop.

React’s Flight implementation walks chunk references recursively, following each `"$n"` pointer until it reaches a terminal value. The vulnerable versions never perform robust cycle detection, so the resolver just keeps chasing the same two chunks forever. That infinite loop happens inside the request handler, so the Node.js event loop or equivalent runtime thread never returns to serve other clients.

On a Next.js 16.0.8 demo app, Better Stack shows the impact in real time. One crafted POST causes the initial connection to stall for 20+ seconds, then every subsequent GET request to `/` times out. From the outside, the site looks “down,” but the container or VM still reports as “running” while its CPU spins on a single poisoned request.

The blast radius is larger than it sounds. React’s own advisory lists react-server-dom-webpack and its siblings (Parcel, Turbopack) in versions 19.0.0–19.2.0, which underpin Next.js 15.x and 16.x, React Router’s RSC support, Waku, Redwood’s SDK, and various bundler plugins. Any app that supports React Server Components inherits the vulnerable deserializer.

Most alarming: you do not need to opt into fancy server actions to be exposed. Better Stack demonstrates the DoS against a stock `create-next-app` project with zero custom actions or business logic. If the runtime exposes a Server Functions endpoint at all, a hostile POST can turn that default install into a self‑DoS button.

Your Server's Secrets, Exposed

React’s second new bug is quieter than a crashed server, but no less unsettling: a crafted POST can make your backend literally quote its own source code back to the attacker. CVE-2025-55183, rated CVSS 5.3 (Medium), targets Server Actions in React Server Components and Next.js, and it exploits how React’s Flight protocol deserializes function references.

Instead of going after data, the attacker goes after behavior. By abusing the Flight wire format, they can convince the deserializer to pass a server action function as an argument to that same function. No type checks trigger, no auth bypass is required, and the call proceeds as if it were a normal request.

Here’s where JavaScript itself turns against you. When a function gets coerced to a string—via template literals, concatenation, or explicit `toString()`—JavaScript’s default Function.prototype.toString() returns the function’s source code. If your server action logs the argument, interpolates it into a response, or stores it as text, the framework dutifully embeds the full function body into the HTTP response.

In Better Stack’s demo, a `submitName` server action that writes to a database ends up echoing its entire implementation after a single malicious POST. The payload marks an argument as a `$F` “server function” reference, then points that reference back at the `submitName` function itself. When React resolves the chunks, the function receives itself as its own `name` parameter, and any stringification leaks code.

Scope-wise, this is not an instant credential dump. Properly handled environment variables—accessed via `process.env` or platform-specific config—do not leak directly, because the vulnerability exposes source, not runtime memory. If you avoid hardcoding API keys, tokens, or passwords into your server actions, those secrets remain out of reach.

What you do lose is business logic: database queries, feature flags, proprietary algorithms, and internal comments all become visible. Attackers can map your data model, infer authorization assumptions, and prepare more targeted exploits. React’s own advisory, Denial of Service and Source Code Exposure in React Server Components, stresses that this is an intellectual property and application-mapping problem, not a direct RCE.

React’s fix is almost embarrassingly small. The patch overrides the default `toString()` for server references with a stub that always returns `"function /* emitted code */"`, severing the link between function values and their original source text.

The Achilles' Heel: Inside React Flight's Deserialization

React’s recent RCE, the new DoS, and the source code leak all orbit a single gravitational center: React Flight. Three different CVEs, three different impacts—remote code execution, total server hang, and server action disclosure—yet they all exploit how Flight deserializes data streaming over HTTP. When Meta’s own advisory quietly points at “React Server Components packages,” it is really pointing at Flight’s wire format as the Achilles’ heel.

React Flight exists to stream a component tree as data, not HTML. On the server, React walks the tree and emits a sequence of “chunks” describing elements, props, and references; on the client or another server, React consumes those chunks and reconstructs the tree. That streaming design underpins React Server Components (RSCs) in Next.js 15/16, React Router, Waku, and others.

Each chunk carries an ID and a JSON-like payload that can reference other chunks using a special "$" notation. A value like `"$1"` means “this field is actually whatever lives in chunk 1,” while `"$f1"` might mean “this is a server function reference with ID 1.” Flight then walks these references, resolving them into a final object graph that React can render or use to call Server Actions.

That indirection is incredibly powerful. It lets React stream partial trees, lazily hydrate components, and pass around server functions by ID instead of shipping their code. But it also means the deserializer must trust, then chase, arbitrary `"$"` references coming from the network—exactly where things went off the rails.

The DoS exploit abuses this by crafting a tiny cycle: chunk 0 points to chunk 1, chunk 1 points back to chunk 0. Before the Dec 11 patch, Flight would follow those `"$"` pointers forever, pinning a Node.js process in an infinite loop and turning a single unauthenticated POST into a full denial of service. React’s fix adds cycle tracking and a hard limit (1,000 dereferences) before it bails out.

The source code leak rides the same mechanism, but with `"$f1"` server function references. By smuggling a reference to the target Server Action into its own argument position, the attacker coerces React into passing the function object where a string should go. JavaScript’s implicit `toString()` on functions then dutifully returns the function’s source code, which Flight happily serializes back to the client.

Put together with last week’s RCE, these bugs show that Flight’s `"$"` reference system—central to RSC’s magic—is also its broadest attack surface. Every cross-chunk pointer expands the graph the server must trust, traverse, and defend.

How Devs Scrambled to Plug the Holes

Illustration: How Devs Scrambled to Plug the Holes
Illustration: How Devs Scrambled to Plug the Holes

React’s patch story for this round of bugs reads like a live-fire exercise in incident response. After reports of the DoS vulnerability landed via Meta’s bug bounty, the team rushed out an initial fix that tried to be clever: track every chunk reference explored during React Flight deserialization and, on revisiting a seen reference, stop walking it and reuse the existing ID instead of following it again.

That first patch shipped, but researchers quickly showed it didn’t close every path to an infinite loop. Cyclic structures like “chunk 0 → chunk 1 → chunk 0” could still push the deserializer into pathological behavior, tying up a Node.js process for 20+ seconds or more. Result: a second advisory, a second CVE, and a second scramble to get new builds into ecosystems like Next.js, React Router, and Waku.

React’s second attempt dropped the sophistication and went for a blunt, testable guarantee. The final DoS fix adds a hard-coded cycle protection counter inside the Flight resolver; once deserialization iterates through references more than 1000 times, it errors out and aborts the request. That single integer limit—1000—turns an unbounded algorithmic risk into a predictable failure mode.

By contrast, the source code leak patch feels almost embarrassingly simple. The bug relied on passing a server action function as its own argument, then coercing that argument to a string, which in JavaScript returns the function’s source. React now overrides the default `toString()` for server references with a custom implementation that always returns a generic string like `function /* omitted code */`.

That one-line behavioral change neuters the entire exploit chain. Attackers can still trick the system into stringifying a reference, but they only ever see placeholder text, not proprietary logic or stray hardcoded secrets. No protocol overhaul, no major refactor—just a safer default.

Together, these patches highlight the tension between reactive security and proactive design. React Flight’s complexity left little room for elegant, formally verified defenses under pressure, so the team shipped pragmatic guardrails: a magic number and a safer `toString()`. It works, but it also underlines how fragile high-complexity serialization protocols become once attackers start treating them as an attack surface, not an implementation detail.

The Blast Radius: A Checklist for Your Stack

React developers need to treat this like a fire drill, not a routine patch. The blast radius covers every app using React Server Components on React 19.0.0–19.2.0, via `react-server-dom-webpack`, `react-server-dom-parcel`, or `react-server-dom-turbopack`. If your stack speaks React Flight, assume exposure until you prove otherwise.

Start with frameworks. Next.js 15.x and 16.x using the App Router and RSCs are in scope, even if you never wrote a single Server Action. Waku, RedwoodJS (Redwood SDK with RSC), and experimental React Router RSC integrations also sit on top of the same vulnerable protocol.

Use this checklist to size up your risk quickly: - Are you running React 19.0.0–19.2.0 in production? - Do you have `react-server-dom-*` packages in `dependencies`, not just `devDependencies`? - Are you using Next.js App Router (13.4+), Waku, RedwoodJS, or any RSC-enabled router? - Do you expose any Server Actions or Server Functions endpoints to the public internet? - Can unauthenticated clients send POST requests to those endpoints?

If you answer “yes” to RSCs or App Router, you are exposed to the high-severity DoS (CVE-2025-55184, CVE-2025-67779). That attack only needs RSC deserialization enabled; it does not care whether you defined custom Server Actions. Any cyclic chunk reference can hang your Node process and starve every other request.

Risk from the source code exposure bug (CVE-2025-55183) narrows slightly. You must have Server Actions, and an attacker needs to target those endpoints specifically to coerce your server into stringifying the function body. That still leaks proprietary logic and any secrets you hardcoded directly into functions.

For exact upgrade paths and patched versions, read Vercel’s Security Bulletin: CVE-2025-55184 and CVE-2025-55183 alongside the React Blog advisory on denial of service and source code exposure. Treat both as mandatory reading before your next deploy.

Deserialization: The Web's Silent Killer

Deserialization bugs rarely make headlines, but security teams quietly rank them among the nastiest flaws in modern software. Any time an app takes structured data from outside—JSON, binary blobs, serialized objects—and turns it back into live objects, untrusted input becomes a potential execution path. React Flight just joined a long list of systems burned by assuming incoming data behaves nicely.

Security vendors have been warning about this for years. Trend Micro calls insecure deserialization “a major attack vector” because it often sits deep in frameworks, far from application code, and attackers only need one weird payload to trigger chaos. OWASP still lists deserialization issues as a top-tier risk, precisely because they routinely lead to RCE, data exposure, or full outages.

Java developers learned this the hard way. The Log4Shell disaster (CVE-2021-44228) started as a logging feature that deserialized attacker-controlled strings into JNDI lookups, then into arbitrary code execution across millions of servers. Before that, Java serialization bugs in libraries like Apache Commons Collections powered years of gadget-chain exploits, all from feeding crafted objects into “trusted” deserializers.

Web stacks keep repeating the pattern. PHP’s unserialize, Python’s pickle, Ruby’s Marshal, .NET’s BinaryFormatter, and now React Flight’s chunk protocol all share the same fundamental problem: they recreate complex object graphs from data an attacker can shape. If that graph can reference code, resources, or recursive structures, someone will eventually weaponize it.

Defenses have to start with a hostile mindset. Assume any client-controlled payload—HTTP bodies, cookies, headers, WebSocket frames—arrives malicious by default. Before deserializing, enforce:

  • Strict schema validation (types, allowed fields, size limits)
  • Integrity checks (HMAC signatures, nonces, version tags)
  • Hard caps on nesting depth, reference chains, and total payload size

Safer designs avoid general-purpose object deserialization entirely. Prefer narrow, versioned formats that map to simple data types, not arbitrary classes or functions. When you must deserialize richer structures, keep that code path isolated, audited, and instrumented, with logging aggressive enough to spot weird graphs long before someone turns them into the next Log4Shell—or the next React Flight CVE.

The Researchers Who Found the Cracks

Illustration: The Researchers Who Found the Cracks
Illustration: The Researchers Who Found the Cracks

Security research rarely looks glamorous, but this wave of bugs has clear protagonists: Andrew MacPherson, RyotaK from GMO Flatt Security, and Shinsaku Nomura from Bitforest. All three reported their findings through Meta’s bug bounty pipeline in early December, just days after React shipped a fix for a critical RCE in React Server Components.

Once CVE-2025-55182, the RCE, went public on December 3, scrutiny on the React Flight protocol spiked. Between December 7 and 11, researchers independently uncovered the denial-of-service loop (CVE-2025-55184, later joined by CVE-2025-67779) and the source code exposure bug (CVE-2025-55183), all within the same deserialization machinery.

React’s own postmortem on the React Blog acknowledges this pattern directly. “Major vulnerabilities almost always trigger a second wave of discoveries in the same area,” the team wrote, arguing that once one invariant breaks, researchers and attackers alike start tugging on every nearby thread.

That dynamic played out here in fast motion. MacPherson focused on how server functions turned into strings could spill code, while RyotaK and Nomura probed Flight’s reference resolution until they hit a trivial infinite loop that could freeze any Node.js process speaking the protocol.

Open-source dynamics amplified this pressure. React’s server internals live on GitHub; once the RCE patch landed, security engineers, tool vendors, and hobbyists all began diffing commits, fuzzing inputs, and replaying malformed Flight streams against Next.js 15.x and 16.x apps.

Bug bounty economics helped keep that energy pointed in the right direction. Meta’s program pays for issues in React’s ecosystem, so researchers had both a financial and reputational reason to stay on the protocol after the first CVE. That combination—transparent code, public incidents, and structured rewards—turned one catastrophic bug into a full structural audit that React’s server stack clearly needed.

Your 3-Step Plan to Secure Your App Now

Step one is IDENTIFY. You need to know exactly which apps, services, and environments are running vulnerable React Server DOM bits before anything else, including staging and internal tools that “nobody uses.” Start by searching your repos for `react-server-dom-` and frameworks that bundle it: Next.js 15.x/16.x App Router, Waku, RedwoodJS, or custom RSC integrations.

Open `package.json` and your lockfile (`package-lock.json`, `yarn.lock`, or `pnpm-lock.yaml`). You are at risk if you see `react-server-dom-webpack`, `react-server-dom-turbopack`, or `react-server-dom-parcel` between `19.0.0` and `19.2.0`, or a framework release that depends on those versions. CI images and Dockerfiles often pin older tags, so check those too.

Step two is UPGRADE. For most Next.js apps, you want the latest patched 15.x or 16.x, which pulls in fixed React Server DOM packages and React Flight deserialization changes. Typical commands look like:

  • `npm install next@latest react@latest react-dom@latest`
  • `yarn add next@latest react@latest react-dom@latest`
  • `pnpm add next@latest react@latest react-dom@latest`

Monorepos need synchronized upgrades across workspaces; don’t leave one service on a vulnerable minor. If you use Waku, RedwoodJS, or custom RSC plugins for Vite/Parcel, follow their security advisories and bump to the first release dated after 2025-12-11 that mentions the DoS and source code leak fixes. For background on the earlier RCE, the React team details the chain in Critical Security Vulnerability in React Server Components.

Step three is VERIFY. Run your full test suite, but prioritize end-to-end flows that exercise Server Actions, streaming responses, and any custom `fetch` or middleware that touches POST endpoints. Watch for subtle regressions around serialization, especially if you pass complex objects, Dates, or custom classes through React Flight.

Deploy to staging and hammer it with load tests and synthetic POST requests against Server Functions endpoints. After rollout, monitor CPU, latency, and error rates for at least 24–48 hours, and scan logs for unexpected “cycle protection” or “server reference” errors. Only when production stays stable under real traffic should you mark this incident closed.

Will React Server Components Ever Be Safe?

React Server Components promised a cleaner mental model for data fetching, fewer client bundles, and faster page loads. After an RCE (CVSS 10.0), a DoS (7.5), and a source leak (5.3) in barely two weeks, they now look like a high‑risk experiment running in production at internet scale.

Under the hood, React Flight behaves less like a simple rendering protocol and more like a custom RPC and serialization layer. Once you treat arbitrary POST bodies as instructions to hydrate server functions, every parsing mistake becomes a potential RCE, DoS, or data exposure.

Performance‑wise, RSCs still deliver: fewer client JavaScript kilobytes, less waterfall fetching, and more cacheable HTML. Developer experience improves too, with Server Actions hiding fetch boilerplate and collapsing API routes into function calls.

Security flips that story. Each new feature—Server Functions, cross‑chunk references, function IDs—extends the attack surface. The DoS loop (chunk 0 → 1 → 0) and function‑as‑argument source leak show how a single missing guard in deserialization logic can knock over an entire Next.js 16.0.8 app with one unauthenticated POST.

React now operates as backend infrastructure, not just a view layer. That shift demands backend‑grade safeguards: formal threat models, fuzzing of the Flight parser, and aggressive limits on recursion, payload size, and reference depth, not just a hardcoded “1000 cycles” escape hatch.

React and Vercel already invest heavily in DX testing and performance benchmarks. They need the same intensity for security: recurring third‑party audits of the Flight protocol, red‑team exercises against Server Functions endpoints, and architectural reviews before each new capability ships.

Framework vendors should treat Flight as a critical dependency, not a black box. That means independent parsers or wrappers that enforce local safety policies, default rate limiting on RSC endpoints, and clear configuration flags to disable or scope RSCs in high‑risk environments.

Developers will keep adopting RSCs because the ergonomics are real and the performance numbers matter to product teams. The question is whether the ecosystem can turn this rough launch period into a durable security story instead of a recurring CVE cycle.

If React, Vercel, and hosting providers respond with sustained investment—bug bounties, protocol specs hardened through community review, and safer defaults—this painful run of CVEs may age into a case study. Server‑side React could emerge not just faster, but measurably safer than the ad‑hoc JSON APIs it aims to replace.

Frequently Asked Questions

What are the two new React vulnerabilities discovered in December 2025?

They are a high-severity Denial of Service (DoS) vulnerability (CVE-2025-55184, CVE-2025-67779) and a medium-severity source code exposure vulnerability (CVE-2025-55183), both affecting React Server Components.

Which versions of Next.js and React are affected?

The vulnerabilities affect React Server Components packages from version 19.0.0 to 19.2.0. This impacts frameworks like Next.js (versions 15.x and 16.x using the App Router), Waku, and RedwoodJS.

Does the patch for the previous critical RCE vulnerability (CVE-2025-55182) protect against these new flaws?

No. The previous patch does not solve these two new vulnerabilities. You must upgrade your dependencies again to receive the specific fixes for the DoS and source code leak issues.

How can I protect my application from these vulnerabilities?

The primary solution is to upgrade your dependencies immediately. For Next.js users, this means upgrading to the latest patched version. Check the official security bulletins from React and your framework provider for specific version numbers.

Tags

#react#nextjs#security#cve#vulnerability

Stay Ahead of the AI Curve

Discover the best AI tools, agents, and MCP servers curated by Stork.AI. Find the right solutions to supercharge your workflow.