React 19.0.0–19.2.0 allows arbitrary server-side code execution through prototype chain traversal in the RSC "Flight" protocol deserializer. No Server Actions required.
constructor key to reach global Function constructorhasOwnProperty checks on all module exports and chunk initializations.requireModule(), the code does moduleExports[metadata[2]] — direct bracket access — without checking if the key is an own property. This allows prototype chain traversal via keys like constructor, enabling access to the global Function constructor. The attack chains $@ (self-reference creating thenable/promise-like objects) with _prefix (holds attacker code string) — new Function("_prefix")() runs with full server privileges. The vulnerability exists in ANY app with RSC enabled; explicit Server Actions are NOT required.
"constructor".requireModule(moduleExports, "constructor") is called. Since "constructor" is not an own property of moduleExports, JavaScript looks up the prototype chain and returns the global Function constructor.$@ (self-reference marker) and _prefix (malicious code string). The deserializer recognizes $@ as a thenable trigger.new Function("_prefix")() is constructed and called — the code in _prefix runs with the Node.js process's full permissions on the server.process.env (AWS/GCP/Azure keys), accesses IMDS at 169.254.169.254 for IAM role credentials, deploys cryptomining (XMRig), or installs C2 backdoors (Sliver framework).process.env. IAM role credentials via IMDS at 169.254.169.254.moduleExports[id] is idiomatic. Direct bracket access on an object is normal JavaScript. It looks correct in isolation — the vulnerability only emerges when you know the input is attacker-controlled.requireModule → reviveModel → initializeModelChunk, with protocol-specific mechanics ($@ self-ref, Flight chunk format) — too complex for a linear diff review.Function constructor is a niche, severe attack class most reviewers don't model.requireModule(), reviveModel(), and initializeModelChunk(). PullLight models the full deserialization pipeline, not just the changed function.moduleExports["constructor"] resolves to the global Function requires understanding JavaScript's prototype chain in a server-side context — a subtle but critical distinction.CVSS 10.0 is not a typo. This is the maximum possible severity in the CVSS scoring system — reserved for vulnerabilities that are trivially exploitable and cause total system compromise. React2Shell meets every criteria: network-accessible, no authentication required, arbitrary code execution, scope change confirmed.
The window between disclosure and active exploitation was measured in hours. The China-nexus APT groups Earth Lamia and Jackpot Panda had working exploits within 12 hours of public disclosure. Cryptomining payloads were observed on unpatched servers within 24 hours. This is what a real-world zero-day looks like — and it started with a React server component.
React Server Components are now the default architecture for Next.js App Router applications. That's millions of production deployments that suddenly needed emergency patching. PullLight's analysis catches this class of vulnerability — prototype chain traversal in deserialization — before it reaches production, because it models the data flow, not just the code syntax.
The fix is simple (hasOwnProperty checks), but the discovery required understanding the full RSC Flight protocol, the JavaScript prototype chain, and the specific attack chain (constructor + $@ + _prefix → new Function()). That's the kind of bug that hides in framework internals and only becomes visible when you model the entire system — not just the changed lines.
Unvalidated property access on untrusted input.
moduleExports[id]inrequireModule()is called without ahasOwnPropertycheck, allowing prototype chain traversal. An attacker supplying"constructor"reaches the globalFunctionconstructor, enabling arbitrary code execution (RCE). The attack chains$@(thenable self-reference) and_prefix(code string) —new Function("_prefix")()runs on the server with full Node.js process privileges.This is a CWE-502 (Deserialization of Untrusted Data) vulnerability with a CVSS 10.0 rating. It affects ANY app with React Server Components enabled — explicit Server Actions are NOT required.
if (!Object.hasOwn(moduleExports, id)) throw new Error('Invalid export')torequireModule(). Also guardreviveModel()against prototype pollution andinitializeModelChunk()against inherited.thenproperties. Patch: React 19.0.1/19.1.2/19.2.1, Next.js 15.0.5+/16.0.7+.