React2Shell is the kind of incident that turns a quiet December into a sprint. Disclosed on December 3, 2025 as CVE‑2025‑55182, it’s a pre‑auth RCE in React Server Components (RSC). A week later, on December 11, two additional issues surfaced: a denial‑of‑service vector and a source‑code exposure flaw. If you only patched once, you may still be exposed. This guide lays out the exact versions to land, how to prove your fixes stick, and a seven‑day plan to close gaps—fast.
What changed since December 3—and why it matters
On December 3, 2025, the React team shipped fixes for a critical deserialization flaw in the RSC Flight protocol that allowed unauthenticated remote code execution. The safe React server packages were published as 19.0.1, 19.1.2, and 19.2.1. Many teams upgraded and exhaled. But on December 11, additional research revealed two more issues in the same area: a high‑severity DoS and a medium‑severity source code exposure. React responded by backporting complete fixes to 19.0.3, 19.1.4, and 19.2.3—superseding the earlier patches.
Next.js, which vendors React and implements App Router on top of RSC, released its own patched lines. If you’re on Next.js 16, the safe baseline is 16.0.7 or newer; on 15, the safe baselines include 15.0.5, 15.1.9, 15.2.6, 15.3.6, 15.4.8, and 15.5.7, with follow‑on DoS fixes later in the month (for example 15.0.7+ and 16.0.10+ when the incomplete DoS fix was addressed). The point is simple: double‑check you’re on the latest patch level for your line. Don’t assume the first December upgrade was enough.
Hosting platforms added guardrails, too. On December 5, Vercel began blocking new deploys that included vulnerable Next.js versions by default. That’s helpful, but it doesn’t retroactively fix existing assets across your fleet or other providers. Treat platform protections as seatbelts, not airbags: useful, but not a strategy.
Who’s affected and how to confirm quickly
You’re affected if your app supports React Server Components on the server. That includes React 19 applications using react-server-dom-* packages, and frameworks that implement RSC—most notably Next.js with the App Router. Even if you don’t think you’ve written “server actions,” the runtime paths exist. Default configs are enough to be in scope.
Fast confirm: three checks in 15 minutes
Run these in parallel—don’t wait for perfect inventory:
1) Source of truth in code: search your dependency tree.
- If you own React directly, look for react-server-dom-webpack, react-server-dom-parcel, or react-server-dom-turbopack. Ensure you’re at 19.0.3, 19.1.4, or 19.2.3. Anything lower invites trouble.
- If you’re on Next.js with the App Router, check package.json and lockfiles; confirm you’ve landed a patched version line (e.g., 16.0.10+ or the fixed 15.x lines that include the follow‑up DoS remediation).
2) Production reality: interrogate the running app. Fetch the server build manifest path or health endpoint that exposes the Next.js version at runtime (common in internal status pages). If your platform strips this, deploy a minimal endpoint that logs the build’s exact dependency resolution.
3) Supply chain: SBOM and artifact scan. Generate a software bill of materials for your production image (Syft or similar) and record the exact versions shipped. This is the evidence auditors will ask for later.
React2Shell patch matrix you can apply today
Here’s the concise map most teams need:
- React Server Components: use 19.0.3, 19.1.4, or 19.2.3 of the react-server-dom-* packages. Earlier point releases from December (like 19.0.1 or 19.1.2) addressed the RCE but missed parts of the DoS chain.
- Next.js (App Router): target 16.0.10+ on the 16 line. On the 15 line, ensure you’re on a release that includes the DoS follow‑ups (for many teams that meant advancing beyond the initial 15.0.5/15.5.7 set). When in doubt, move to the latest stable in your minor—don’t cherry‑pick.
- Hosting protection: Vercel blocks new deploys with unsupported versions, but you can bypass it. Don’t. If you must for a hotfix, treat that bypass as a Sev‑1 risk and remove it immediately after patching.
- Bundlers and plugins: if you use RSC via Parcel or Vite plugins, verify their patched versions and confirm your lockfile actually pulled the fixed React server packages.
How React2Shell actually works—without the hand‑waving
The RSC Flight protocol serializes a component tree and server actions between client and server. The original bug lived in deserialization on the server: crafted payloads could be accepted as valid and resolve to dangerous objects, enabling arbitrary command execution in process. The DoS variant abused code paths that could be coerced into infinite loops, pinning CPU. The source‑exposure issue let attackers read server‑side source artifacts they shouldn’t. All three stem from the same trust boundary mistake: the server treated Flight payloads as if they were always well‑formed and trusted.
“We patched last week—how do we prove we’re safe?”
Here’s the thing: a lot of teams patched once and moved on. December 11 changed the bar. You need proof that the currently deployed bits are fixed. Use this four‑layer evidence model; it’s quick to assemble and stands up under scrutiny.
Layer 1: Dependency proof
- Attach the npm ls or pnpm list output for the react-server-dom-* packages and Next.js to your change ticket. Make sure the versions match the fixed lines above.
- Include the lockfile diff showing the exact upgrade and integrity hashes. That diff is gold during incident review.
Layer 2: Build artifact proof
- Produce an SBOM for the built container or serverless artifact. Store it with the release notes.
- Keep a signed attestation (SLSA‑style) from CI that captures the dependency graph at build time.
Layer 3: Runtime proof
- Expose a read‑only endpoint that returns the application version and the Next.js/React RSC versions at startup. Gate it behind auth if you must, but make it queryable.
- Add a smoke test that hits a known Server Action with a benign malformed payload. The fixed runtime should reject it without hanging or executing anything.
Layer 4: Log proof
- Enable structured logs for RSC deserialization errors and timeouts. Configure alerts for repeated patterns, which often indicate exploitation attempts. Store a 30‑day lookback so you can demonstrate no successful exploitation occurred post‑patch.
People also ask
Does a WAF or CDN rule save me from React2Shell?
No. Some providers ship helpful signatures, but RSC payloads aren’t a simple string match. Treat WAFs as defense in depth while you patch. If your WAF has a togglable “React2Shell” rule set, enable it—but still upgrade.
Are client‑only React apps vulnerable?
Pure client‑side React—no RSC on a server—doesn’t expose the vulnerable code paths. That said, many “frontend” apps quietly use server actions through their framework. Verify, don’t assume.
What about React 18?
React 18 apps that don’t enable RSC aren’t impacted by the RSC deserialization bugs. If you’ve adopted community backports or experimental RSC builds with React 18, reassess with your maintainers and advance to the fixed React 19 server packages.
Let’s get practical: a 7‑day React2Shell plan
Time‑boxing the work keeps you from dragging this into January. Here’s a plan you can start today.
Day 1: Inventory and freeze
- Collect all services using Next.js App Router or RSC. Freeze non‑security deploys for those repos.
- Assign owners and create one tracking ticket per service with a checklist.
Day 2: Land the upgrades
- For React RSC: upgrade to 19.0.3, 19.1.4, or 19.2.3—whichever matches your minor line.
- For Next.js: move to the latest patch in your current minor line that includes the DoS follow‑up. If friction is high, jump to the newest compatible minor rather than babysitting older patches.
Day 3: Verify in staging like an attacker
- Run a PoC in a safe environment to validate the fix. Pair this with profiling to confirm no CPU pinning occurs.
- Add a negative test to CI that sends malformed Flight payloads and expects rejection.
Day 4: Roll to production with guardrails
- Use canaries. Roll out to 5–10% traffic, watch error rates and CPU. Bake for an hour before going to 50% and then 100%.
- Keep autoscaling conservative to catch unexpected CPU churn that might hide a DoS regression.
Day 5: Close the gaps
- Scan for orphan environments: old PR previews, sandboxes, or cron‑only services still on vulnerable images.
- Rotate any credentials that originated from affected hosts since December 3 if you saw suspicious logs.
Day 6: Evidence pack
- Export SBOMs, lockfile diffs, CI attestations, and canary graphs. Drop them in a single, shareable folder tied to the incident ticket.
- Draft a short internal memo: dates, versions, repos, owners, proof. You’ll be asked—make it easy.
Day 7: Make it stick
- Add a weekly job that fails the build if vulnerable RSC or Next.js versions reappear.
- Add runtime version reporting to your status endpoint and wire a dashboard that turns red if it drifts.
Common traps we’re seeing
- Patching only the top‑level react or react-dom package and ignoring the react-server-dom-* packages. The vulnerable code lives in the server packages; upgrade those explicitly.
- Believing an initial December patch is enough. If you stopped at 19.0.1/19.1.2/19.2.1 or the first round of Next.js fixes, you missed the DoS follow‑up. Move to 19.0.3/19.1.4/19.2.3 or their Next.js equivalents.
- Monorepo foot‑guns. Mixed clients accidentally import the old server packages through hoisting. Pin and verify at the workspace root and at each app’s lockfile.
- “Temporary” platform bypasses. Some platforms let you skip the block on vulnerable builds with a single environment variable. That’s a short path to regret—strip it as soon as the fix lands.
- Assuming “no server actions” means “no risk.” The RSC runtime can be reachable even if you aren’t calling it directly.
A lightweight control framework you can reuse
Borrow this PATCH‑PROVE‑LOCK loop for React2Shell and the next CVE:
PATCH
- Upgrade the exact vulnerable components and their vendors (React RSC packages, Next.js lines, bundler plugins).
- Land the fix in production with canaries and platform rules turned on.
PROVE
- Capture lockfile diffs, SBOMs, CI attestations, and runtime version endpoints.
- Run negative tests and capture the outputs. Store them with the release.
LOCK
- Add build‑time policies that fail on vulnerable versions.
- Add runtime drift detection and alerting when versions change or protections are disabled.
Data you can take to your execs today
- Disclosure date: December 3, 2025 (RCE in RSC). Additional issues disclosed December 11, 2025 (DoS and source exposure).
- Minimum safe React server packages: 19.0.3, 19.1.4, 19.2.3.
- Representative safe Next.js lines: 16.0.10+ on the 16 line; 15.x lines released after December 11 that include the follow‑up DoS fix.
- Platform stance: major hosting providers added protections (e.g., blocking vulnerable Next.js deploys starting December 5 for some). These don’t retro‑patch your running apps.
What to do next
- If you’re still investigating, use our holiday patch playbook to organize owners, repos, and deadlines.
- Already patched once? Cross‑check with our short guide on what changed this week and how to prove fixes, then collect your evidence pack.
- Fighting fire during the holidays? The patch fast, prove safety, avoid traps checklist covers the gotchas we keep seeing in the field.
- If you need help triaging or want a second set of eyes on your deployment posture, reach out via our contact page. We can review your versions, CI evidence, and rollout plan in a single working session.
Zooming out
React Server Components aren’t going away; they’re a powerful model with real performance wins. But anytime a UI framework starts speaking a private protocol to your server, that protocol becomes part of your attack surface. React2Shell won’t be the last lesson here. Invest in a version‑aware pipeline, runtime drift detection, and simple proofs you can hand to auditors—or to your future self when you’re on call at 2 a.m.
Ship the fixes. Prove them. Lock them in. Then enjoy your holiday—and your sleep.
