Someone can spin your server's CPU in circles by mailing it a riddle that references itself
CVE-2026-23869 is a denial-of-service flaw in React Server Components' Flight protocol — the binary wire format React uses to stream server-rendered UI to the client. The vulnerable code lives in ReactFlightReplyServer.js, specifically in the createMap, createSet, and extractIterator functions, which fail to detect cyclic references during deserialization of incoming HTTP request payloads. An attacker sends a crafted POST to any Server Function endpoint (a.k.a. Server Action); the server enters a CPU-bound loop for roughly 60 seconds before throwing a catchable error. Affected packages are react-server-dom-webpack, react-server-dom-parcel, and react-server-dom-turbopack in versions 19.0.0–19.0.4, 19.1.0–19.1.5, and 19.2.0–19.2.4. Downstream, Next.js 13.x through 16.x with App Router enabled inherits the bug. Fixed in React 19.0.5 / 19.1.6 / 19.2.5 and Next.js 15.5.15 / 16.2.3.
Meta scored this 7.5 HIGH, which is technically accurate per CVSS’s availability-only, unauthenticated-remote formula. In practice, the severity is softer than that label implies. The impact is availability-only — no code execution, no data leak, no lateral movement. Each malicious request burns one CPU core for ~60 seconds then *self-recovers* via a catchable exception; the process does not crash. Standard reverse-proxy rate limiting, WAF virtual patches (Fastly and Vercel both shipped them), and cloud auto-scaling blunt the attack significantly. There is no public PoC, no KEV listing, and EPSS sits at 1.55% — all pointing to low real-world exploitation pressure. For a fleet manager triaging against RCE and privilege-escalation vulns, this is a MEDIUM that belongs in the regular remediation cycle, not an emergency.
4 steps from start to impact.
Identify a Server Function endpoint
/_next/ routes. No authentication is required.- Target runs React 19.x with Server Components enabled
- Server Function endpoint is network-reachable
- Server Functions are only present in apps that opted into React 19 RSC — not all React apps use them
- Apps behind CDN edge caching may not forward arbitrary POSTs to origin
x-powered-by, x-nextjs-*). Shodan/FOFA dorks for Next.js are well-known.Craft a cyclic deserialization payload
- Knowledge of React Flight reply wire format
- Ability to send arbitrary POST bodies
- No public PoC or exploit tool exists as of September 2026
- The Flight wire format is not formally documented, requiring reverse-engineering from source
Send payload to trigger CPU exhaustion
createMap/createSet/extractIterator functions enter a CPU-bound loop attempting to resolve the cycle. A single request pins one CPU core at 100% for approximately 60 seconds before a catchable error terminates the operation. The process does not crash.- Network access to the endpoint (typically internet-facing)
- Single request = single core for ~60s; sustained DoS requires repeated requests
- Rate limiting at reverse proxy (nginx, Cloudflare, AWS ALB) throttles volume
- Cloud auto-scaling can absorb moderate request bursts
Sustain denial of service
- Sufficient request volume to overcome rate limits and scaling
- Sustained attacker bandwidth and infrastructure
- WAF virtual patches (Fastly, Vercel, Cloudflare) can block the specific payload pattern
- IP-based rate limiting caps per-source volume
- The error is catchable — application frameworks can implement retry/backoff logic that partially self-heals
- Cloud auto-scaling adds capacity during CPU spikes
/_next/ paths or form-action URLs) at a reasonable threshold — e.g., 10–20 requests per second per source IP. This directly breaks step 4 of the attack path by preventing the sustained request volume needed for meaningful DoS. Since this is a MEDIUM verdict, there is no noisgate mitigation SLA — deploy as part of standard hardening within the 365-day remediation window.npm audit fix or npm update in your CI pipeline. This is the definitive fix. Per noisgate remediation SLA for MEDIUM, complete within 365 days, though earlier is better if your deployment pipeline supports it.server.timeout = 30000 in Node.js, or equivalent in your framework config) to kill long-running request handlers before the full ~60s CPU burn completes. This reduces per-request impact from 60s to your timeout threshold, making sustained DoS harder to achieve.- Network-level DDoS protection (e.g., AWS Shield, Cloudflare L3/L4) — This is an application-layer (L7) attack using valid HTTP POST requests, not a volumetric flood. L3/L4 DDoS mitigation will not detect or block it.
- Authentication/authorization on Server Functions — While adding auth would prevent anonymous exploitation, React Server Components’ deserialization occurs *before* application-level auth middleware in most framework configurations. The CPU exhaustion triggers during payload parsing, not during business logic execution.
- Node.js clustering/PM2 restart policies — The process does not crash, so restart-on-failure policies never trigger. The CPU simply stays pinned at 100% for ~60s then recovers normally.
The supporting signals.
| In-the-Wild Exploitation | No known exploitation. Not listed on CISA KEV. No campaigns or threat-actor usage reported as of September 2026. |
|---|---|
| Proof-of-Concept | No public PoC available. No exploit code on GitHub, ExploitDB, or Nuclei templates. Exploitation requires crafting React Flight wire-format payloads, which raises the bar slightly. |
| EPSS Score | 0.01551 (1.55%) — low exploitation probability, well below the 6% threshold that typically signals active concern. |
| KEV Status | Not listed. No CISA Binding Operational Directive applies. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H — unauthenticated remote with high availability impact but zero confidentiality/integrity impact. Classic DoS-only scoring. |
| Affected Versions | react-server-dom-webpack, react-server-dom-parcel, react-server-dom-turbopack: 19.0.0–19.0.4, 19.1.0–19.1.5, 19.2.0–19.2.4. Downstream: Next.js 13.x–16.x with App Router. |
| Fixed Versions | React packages: 19.0.5, 19.1.6, 19.2.5. Next.js: 15.5.15, 16.2.3. npm audit fix or npm update pulls the fix. |
| Scanning / Exposure | Next.js applications are widely discoverable via Shodan (http.component:next.js), FOFA, and Censys. However, only apps using Server Functions (Server Actions) are vulnerable — a subset of the Next.js install base. |
| Disclosure Date | 2026-04-08 (GitHub Security Advisory GHSA-479c-33wc-g2pg). Patches released same day. |
| Reporter | Not publicly credited in the GHSA or React blog. CVE assigned by Meta as CNA. |
Sources.
- GitHub Security Advisory GHSA-479c-33wc-g2pg
- MITRE CVE Record
- Vercel Changelog - Summary of CVE-2026-23869
- Fastly Blog - What is CVE-2026-23869
- CyCognito - React Server Components DoS via Cyclic Deserialization
- Red Hat Customer Portal - CVE-2026-23869
- CIRCL Vulnerability Lookup - GHSA-479c-33wc-g2pg
- OSV - GHSA-479c-33wc-g2pg
Why this verdict
- Availability-only impact caps severity. The CVSS vector explicitly shows C:N/I:N — no data breach, no code execution, no lateral movement. For a fleet manager, this means the blast radius is *service degradation* on a single application, not credential theft or domain compromise.
- Self-recovering behavior. Each malicious request burns ~60 seconds of CPU then throws a *catchable* error. The Node.js process does not crash or restart. This is a transient resource exhaustion, not a persistent denial of service.
- Standard compensating controls are highly effective. Reverse-proxy rate limiting, WAF virtual patches (Fastly and Vercel shipped them within days), and cloud auto-scaling all directly counter this attack. Most production Next.js deployments already have at least one of these in place.
- No exploitation pressure. EPSS is 1.55%, no KEV listing, no public PoC, no observed campaigns. The attack requires knowledge of an undocumented wire format with no available tooling.
- Role multiplier: React Server Components power web application tiers — customer-facing UIs, dashboards, e-commerce storefronts. These are *not* canonical high-value infrastructure roles (not IdP, DC, hypervisor, PAM, backup, CI/CD, or network edge). A DoS on a web app tier does not produce domain takeover, fleet compromise, or supply-chain pivot. The worst plausible high-value outcome is temporary revenue-impacting outage on a customer-facing app, which is a business-continuity concern but not a security-boundary breach. The floor rule does not elevate this beyond MEDIUM.
- Wide deployment is a wash. Next.js is extremely popular, which increases the *population* of potentially affected apps but does not change the per-app impact ceiling. Many Next.js apps don’t use Server Functions at all, narrowing the truly vulnerable subset.
Why not higher?
Upgrading to HIGH would require either a path to code execution, data compromise, or a blast radius beyond the individual application — none of which exist here. The DoS is temporary, self-recovering, and trivially mitigated by rate limiting. No exploitation in the wild and no PoC further reduce urgency. A HIGH rating would misallocate emergency patching resources away from RCE and privilege-escalation vulns that genuinely threaten fleet integrity.
Why not lower?
Dropping to LOW would understate the risk for internet-facing production applications that lack rate limiting. An unauthenticated attacker *can* degrade service availability with minimal effort once the payload format is understood. The wide deployment of Next.js means a non-trivial number of applications are exposed, and the attack requires no credentials or user interaction. MEDIUM correctly signals this belongs in the regular remediation cycle rather than the backlog.
Crowdsourced verification payload.
Run this script on any host where a Node.js application using React Server Components is deployed. Point it at the application root directory (where node_modules lives). Requires read access to the filesystem; no elevated privileges needed. Example: bash cve-2026-23869-check.sh /opt/myapp
#!/bin/bash\n# CVE-2026-23869 Checker - React Server Components DoS\n# Checks installed versions of affected react-server-dom-* packages\n# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN\n\nAPP_DIR=\"${1:-.}\"\nVULN=0\nCHECKED=0\nPACKAGES=(\"react-server-dom-webpack\" \"react-server-dom-parcel\" \"react-server-dom-turbopack\")\n\nif [ ! -d \"$APP_DIR/node_modules\" ]; then\n echo \"UNKNOWN - no node_modules found at $APP_DIR\"\n exit 2\nfi\n\nfor PKG in \"${PACKAGES[@]}\"; do\n PKG_JSON=\"$APP_DIR/node_modules/$PKG/package.json\"\n if [ -f \"$PKG_JSON\" ]; then\n VERSION=$(node -e \"console.log(require('$PKG_JSON').version)\" 2>/dev/null)\n if [ -z \"$VERSION\" ]; then\n continue\n fi\n CHECKED=1\n MAJOR=$(echo \"$VERSION\" | cut -d. -f1)\n MINOR=$(echo \"$VERSION\" | cut -d. -f2)\n PATCH=$(echo \"$VERSION\" | cut -d. -f3)\n if [ \"$MAJOR\" -eq 19 ]; then\n if [ \"$MINOR\" -eq 0 ] && [ \"$PATCH\" -le 4 ]; then\n echo \"VULNERABLE - $PKG@$VERSION (fix: 19.0.5)\"\n VULN=1\n elif [ \"$MINOR\" -eq 1 ] && [ \"$PATCH\" -le 5 ]; then\n echo \"VULNERABLE - $PKG@$VERSION (fix: 19.1.6)\"\n VULN=1\n elif [ \"$MINOR\" -eq 2 ] && [ \"$PATCH\" -le 4 ]; then\n echo \"VULNERABLE - $PKG@$VERSION (fix: 19.2.5)\"\n VULN=1\n else\n echo \"PATCHED - $PKG@$VERSION\"\n fi\n else\n echo \"PATCHED - $PKG@$VERSION (outside affected major)\"\n fi\n fi\ndone\n\nif [ \"$CHECKED\" -eq 0 ]; then\n echo \"UNKNOWN - none of the affected packages found in $APP_DIR\"\n exit 2\nfi\n\nif [ \"$VULN\" -eq 1 ]; then\n exit 1\nelse\n echo \"PATCHED - all detected packages at safe versions\"\n exit 0\nfi