Phaze is secure by design
React is insecure by design — not for lack of care, but because React Server Components are defined by a server/client boundary: components and function arguments are serialized on one side and deserialized on the other, and deserializing untrusted, attacker-controllable input on the far side has produced a steady stream of critical CVEs since December 2025 (the catalogue below). They aren’t isolated mistakes — they’re the wire.
Phaze is secure by design for the mirror reason: it is isomorphic — there is no server/client boundary to serialize across, so the deserialization sink and the bypassable gate have nowhere to exist. This page is the case, item by item.
The catalogue
Section titled “The catalogue”| CVE | Class | Root cause | Scope / status |
|---|---|---|---|
| CVE-2025-55182 (“React2Shell”) | Unauthenticated RCE, CVSS 10.0 | Server-side prototype pollution in the RSC deserializer → arbitrary code via child_process | React 19.0–19.2 / Next 13.3–14.x. On CISA’s Known-Exploited list — in the wild. Patched React 19.0.1/19.1.2/19.2.1, Next 14.2.35 |
| CVE-2025-29927 | Authorization bypass | x-middleware-subrequest header (an internal loop-guard) skips middleware entirely → reach protected routes + _next/data | Patched 12.3.5 / 13.5.9 / 14.2.25 / 15.2.3 |
| Source-code exposure | Information disclosure | Malformed Server Function args cause the function to return its own source when arguments are stringified | Disclosed alongside the Dec 2025 DoS |
| CVE-2026-23864 → -23869 → -23870 (the chain) | Denial of service | Cyclic / pathological deserialization → CPU exhaustion, OOM, process kill | RSC 19.x / all Next App Router 13.x–16.x. Each fix incomplete — a new vector surfaced against the previously-patched versions |
The fourth row is the tell. The December DoS fix was incomplete; CVE-2026-23864 (Jan 2026), -23869 (May 2026), and -23870 (immediately after, against those same “fixed” versions) are the same sink re-found. A security write-up titles it plainly: “DoS Vulnerability That Keeps Coming Back on React Server Components.” You don’t get a recurring sink from a one-off bug — you get it from an architecture.
Two structural surfaces — both born of the server/client split
Section titled “Two structural surfaces — both born of the server/client split”- The serialization boundary. RSC must serialize across server↔client; the deserialize step ingests untrusted input. That is the RCE / DoS / source-exposure sink — and it recurs because it is the wire, not a defect on top of it.
- The detachable gate. Authorization placed in a middleware layer in front of the route is, by definition, a layer that can be skipped (CVE-2025-29927). Next’s own post-incident guidance now says it outright: “middleware should supplement, not replace, robust security measures placed closer to the data source.” That is an admission that the gate-in-front model was the wrong place.
How Phaze removes the surface — isomorphism + declarative mechanics
Section titled “How Phaze removes the surface — isomorphism + declarative mechanics”Every item above lives on the server/client split. Phaze is isomorphic — there is no split — so there is nothing to serialize across, nothing to deserialize, and no separable gate to skip.
| React surface | Phaze structural answer |
|---|---|
| RSC serialize / deserialize wire (the RCE + DoS sink) | No serialization protocol. One universal component runs on both sides — its code ships and runs, it is never serialized into a Flight payload. Data crosses as plain JSON (SSR-seeded, read as a value, never reconstructed) or via a transport action whose first act is input.parse (zod). No object-graph reconstruction → the prototype-pollution / cyclic-deserialization sink has nowhere to live. |
| Closure-captured server data serialized to the client | None. newAction compiles to a bare object literal + an inline fetch arrow — no closure is serialized to the browser, so there is no captured data to leak. |
| Server Function returns its own source on malformed input | No such path. Handlers are server-only code; the client holds a typed fetch, never a serialized function that can reflect its source. |
| Middleware auth bypass (skip the layer, reach the route) | No detachable gate. The restricted guard is a server-only page export run inside the route’s own dispatch (core()) — isomorphism puts server-only logic on the universal page, not in a layer in front of it. There is no hop to skip, and it is “close to the data” — Next’s own remediation, by construction. |
Redirects are an attack surface too — so the gate signs them
Section titled “Redirects are an attack surface too — so the gate signs them”Auth gates classically lean on redirects (302 → /login), and a redirect is an instruction the browser obeys: when its target derives from input (/login?next=…) it’s the textbook open redirect, and even a fixed target can be swapped by a MITM or a poisoned cache. Phaze treats the redirect as surface and shrinks it two ways:
-
Most outcomes don’t redirect at all.
403/404/500render in place at the attempted URL with the real status code — reserved status-code pages (403.phaze/404.phaze/500.phaze) emitted by the in-core()guard. NoLocationheader, no navigation, nothing to tamper with. -
The one flow-redirect (401 → login) is Ed25519-signed, and the browser verifies it for free. The server signs the redirect’s
toreturn-path (with anexpwindow) usingPHAZE_SIGN_KEY; the phaze-router verifies that signature with the public key before following — and because Ed25519 verify is WebCrypto-native, the check costs 0 bytes on the client (the same property behind signed transport). So a redirect the browser honors is provably server-issued; a forged/tamperedLocation— a swappedto=https://evil.com, a MITM, a poisoned cache — is rejected beforelocation.href. The return-path can’t be altered without invalidating the signature, andexpbounds replay of a stale link.
At a glance
Section titled “At a glance”| Surface | React / Next | Phaze |
|---|---|---|
| Deserialization RCE (prototype pollution) | CVE-2025-55182, 10.0, exploited | absent — wire is data, input.parse’d, never reconstructed |
| Deserialization DoS | recurring chain — CVE-2026-23864 / -23869 / -23870 | absent — same reason |
| Source-code exposure | malformed args reflect source | absent — handlers are server-only, no serialized function |
| Closure data leak to client | serialized closures | absent — no closure serialization |
| Auth gate bypass | CVE-2025-29927 (skippable middleware) | absent — restricted guard in core(), no separable layer |
| Auth-redirect tampering / open redirect | unsigned 302, ?next= reflection (known footgun) | Ed25519-signed, browser-verified before follow — or isomorphicAuth (no redirect) |
| Where the risk comes from | the server/client serialization boundary | there is no boundary (isomorphic) |
See also
Section titled “See also”- Hardened Transport — the field-by-field contrast and the cryptographic additions (
sign:/verify:/encrypt:). - Phaze Transport — the typed, schema-validated wire that replaces the RSC protocol.
- Router — isomorphism, SSR-seeding, and the per-route
restrictedguard.