The Recent 0-Days in Node.js and React Were Found by an AI

In December 2025 and January 2026, an AI system autonomously discovered zero-day vulnerabilities in Node.js and React, two of the most widely deployed JavaScript runtimes and frameworks in the world.
These weren't theoretical weaknesses or best-practice violations. They were exploitable security flaws that received CVE identifiers, and required patches from the Node.js and React core teams.
This post documents how these vulnerabilities were found, the technical details of the flaws, and what this means for the future of security research.
The Discoveries
CVE-2026-21636: Node.js Permission Model Bypass via Unix Domain Sockets
Node.js introduced a Permission Model in recent versions - a security sandbox that restricts what code can do when run with the --permission flag. Think of it as Node's attempt to let you run untrusted JavaScript with some guarantees: you can allow filesystem access to specific paths, network access to specific domains, and so on.
The vulnerability we discovered breaks this security boundary entirely.
The Bug
When the Permission Model is enabled without --allow-net, you'd expect that the running code cannot make network connections. And for TCP/IP connections, this holds true. But the implementation missed something: Unix Domain Sockets (UDS).
Unix Domain Sockets are a form of inter-process communication that look syntactically similar to network connections but operate entirely on the local filesystem. They're used extensively by databases (PostgreSQL, MySQL, Redis), container runtimes (Docker's /var/run/docker.sock), and countless other privileged services.
The permission checks in Node.js didn't enforce network restrictions for the Unix socket path. When you connect to a UDS via net.connect({ path: '/var/run/docker.sock' }), the permission model didn't intervene.
The implications are severe. An attacker-controlled script that was supposed to be sandboxed could:
- Connect to the Docker socket and spawn privileged containers
- Access database sockets and extract sensitive data
- Communicate with any local service exposing a Unix socket
- Achieve local privilege escalation through socket-accessible services
The fix added permission enforcement on Unix socket connection paths to ensure UDS access is covered.
How We Found It
Our system starts by building a complete understanding of the codebase. Not just the surface-level API, but the internal call graph, the permission checking logic, and the relationship between different subsystems.
For Node.js, this meant understanding that the Permission Model is exposed via lib/internal/process/permission.js and that it hooks into various points in the standard library. The key insight came from analyzing what the permission checks actually check versus what developers assume they check.
The permission model has explicit checks for:
- Filesystem operations (
--allow-fs-read,--allow-fs-write) - Network operations (
--allow-net) - Native addons (
--allow-addons) - Child process spawning (
--allow-child-process) - Inspector access (
--allow-inspector) - WASI (
--allow-wasi) - Worker threads (
--allow-worker)
But "network operations" is an under-specified category. The implementation equated "network" with "TCP/IP", missing that Unix sockets (which use the same API surface) are a distinct capability with distinct security implications.
Our threat modeling agent generated the attack scenario: "If network restrictions only apply to TCP connections, can we bypass the sandbox by connecting to local sockets?" The analysis agent traced the code paths through net.connect() and confirmed that Unix socket connections bypassed the permission checks entirely.
CVE-2026-23864: React Server Components Denial of Service
React Server Components (RSC) represent a fundamental shift in how React applications can be built. Server Components run on the server, render to a special format, and stream to the client. This creates a new attack surface: the protocol between client and server.
The Bug
The vulnerability exists in the RSC reply decoder, the code that parses responses from Server Functions. When a client sends a specially crafted HTTP request to a Server Function endpoint, it can trigger multiple failure modes:
- Infinite loops: Certain payload structures cause the decoder to loop indefinitely, consuming 100% CPU
- Out-of-memory exceptions: Other payloads trigger unbounded memory allocation
- Server crashes: Some variants cause unhandled exceptions that terminate the process
The attack requires no authentication. Endpoints that handle Server Function requests in frameworks using React Server Components are vulnerable to this class of payload.
The technical root cause involves how RSC handles FormData with specific reference patterns. The decoder uses internal markers (like $K) to handle references between serialized objects. By carefully constructing a payload with many $K tokens, an attacker can amplify allocations in the decoder.
This reproduction shows how a small multipart input can expand into large allocations when $K tokens are processed repeatedly.
The impact is significant because:
- Next.js 13+, 14, 15, and 16 are all affected
- react-router, waku, @parcel/rsc, @vitejs/plugin-rsc, and rwsdk are affected
How We Found It
React's RSC implementation is complex. The serialization format is custom, the parsing logic is spread across multiple files, and the interaction between client and server involves multiple layers of abstraction.
Our approach was methodical:
-
Indexing: We built a complete code graph of the
react-server-dom-*packages, mapping how data flows from the HTTP request through the parsing pipeline. -
Threat Modeling: We identified that the reply decoder accepts untrusted input directly from HTTP requests. This made it a high-priority target for adversarial input analysis.
-
Attack Surface Enumeration: We catalogued every code path that could be triggered by malformed input: reference resolution, type parsing, error handling, stream processing.
-
Payload Generation: Using techniques similar to fuzzing but guided by semantic understanding of the protocol, we generated payloads that would exercise edge cases in the decoder logic.
-
Verification: Each candidate vulnerability was verified by actually exploiting it: measuring CPU usage, memory allocation, and process stability.
On AI-Discovered Vulnerabilities
I want to be precise about what happened here and what it means.
What This Is Not
This is not a brute-force fuzzer that got lucky. Fuzzers can find memory corruption bugs in C code by generating millions of random inputs. They're less effective at finding logic bugs, and they struggle with highly structured protocols like RSC's serialization format.
This is not a simple pattern matcher that flagged the code for human review. We didn't generate a report that said "this might be vulnerable"; we generated working exploits and verified the impact.
This is not domain-specific. The same system that found these vulnerabilities has found SQL injection in Supabase, YAML parsing issues in Bun (DoS), and authorization flaws in Gumroad, to list a few. The vulnerabilities span different languages, frameworks, and vulnerability classes. You can see some of our findings on our Hacktivity page.
What This Is
This is an AI system that performs the full cycle of security research:
- Codebase Understanding: Building a semantic model of how the software works, not just what files exist
- Threat Modeling: Generating hypotheses about what could go wrong and why
- Vulnerability Discovery: Finding specific code paths that violate security properties
- Exploitation: Creating proof-of-concept code that demonstrates the vulnerability
- Verification: Confirming that the exploit works and measuring its impact
Each of these steps has traditionally required human expertise. The claim here is that for a meaningful subset of vulnerabilities, including previously-unknown 0-days in major software, an AI can perform all five steps autonomously.
The Significance
Consider what traditional SAST (Static Application Security Testing) tools do: they pattern-match known-vulnerable code patterns. If your code looks like sql.query("SELECT * FROM users WHERE id = " + id), they flag it. Useful, but limited to what humans have explicitly taught them.
And then again, does this id parameter get filtered by a previous function call? Is the function that contains this line even reachable? Most SAST tools lack these important contexts. Leading to a lot of "noise".
Consider what human security researchers do: they understand the purpose of code, reason about edge cases, and find bugs that don't match any known pattern. This is why human penetration testers find vulnerabilities that scanners miss.
The Node.js and React vulnerabilities are examples of the latter category. No scanner was going to flag "Unix sockets bypass network restrictions" because no one had previously documented that pattern in some rule file. It required understanding what the Permission Model was supposed to do, how it was implemented, and where the implementation fell short of the specification.
On "AI Slop"
AI magically finding 0-days would be a fairy tale. As of February 3rd, the current models require quite a bit of supervision and "orchestration" with a tinch of expertise in whatever target domain it's tasked to do some work with. Without it, we'll end up with something called "AI Slop".
In July of 2025, Daniel Stenberg, the author of cURL, wrote a blog post titled "Death by a thousand slops". A follow up of another blog post titled "The I in LLM stands for intelligence".
He writes about the frustrating experience of receiving "bogus" security reports agaist curl.
"Beg bounties" were already a problem. The advent of LLMs and coding agents exacerbated it.
LLMs or the AI models we have at our peril have a "hallucination" problem.
"🚨 CRITICAL VULNERABILITY" (with a siren emoji) exclaims Claude when prompted with "Find security issues in this codebase".
Were any of them real? Nope.
But humans who knows what they're doing can "tame" these models. By hand-holding them to come up with a working PoC and actually verifying them. All while understanding the model didn't just lie to you to get the job done, another trait of these models called "reward hacking".
For a real instance, Andrew MacPherson, a principal security engineer at Privy (a Stripe company), was featured in the OpenAI's GPT 5.2 Codex release post for finding a vulnerability in React (RSC) using Codex, the open-source coding agent harness by OpenAI.
At Winfunc, we're doing exactly this. Just without the hand-holding. No human-in-the-loop. The hand-holding part carefully automated at a larger scale. Read along for how we achieved this.
Technical Architecture
For those interested in how this works, here's a simplified overview of the system architecture.
Indexing
We start by building a language-agnostic code graph. This isn't just an AST; it captures semantic relationships between code elements:
- Call graphs (what function calls what)
- Data flow (how values propagate through the code)
- Type information (what constraints exist on values)
- Control flow (what conditions must hold for code to execute)
This makes sure we're covering full breadth and depth of the complete application flow.
For the Node.js permission model analysis, this meant understanding that net.connect() enforces permissions on TCP/IP paths, while Unix socket paths bypassed those checks before the fix.
Threat Modeling
We generate attack scenarios automatically by reasoning about what the code is supposed to do and what would constitute a security violation. This is where the "AI" part is most distinctive: we use large language models to generate hypotheses that a fuzzer would never produce.
For the React vulnerability, the threat model included: "Can a malicious client craft a payload that causes the server to consume unbounded resources?"
Interestingly, the tendency of LLMs to hallucinate is a very beneficial trait for vulnerability discovery. It crafts "creative" attack scenarios. We've witnessed our agent raise contrived vulnerabilities and the exploitation agent finding clever attack vectors that were only possible via chaining another vulnerabiltiy in the codebase. The "tryhard" agent made the hallucination a reality. A lot of misses with this approach but the hits... hits.
Analysis and Exploitation
Once we have a hypothesis, we analyze whether the codebase is actually vulnerable and, if so, generate an exploit. This involves:
- Tracing code paths to verify the vulnerability exists
- Understanding constraints on inputs (what format they must follow)
- Generating payloads that satisfy those constraints while triggering the bug
- Verifying the exploit in a sandboxed environment
The Monte Carlo Tree Self-Refine (arXiv:2406.07394) approach we published previously was designed for this step: iteratively refining exploit payloads based on execution feedback.
Verification
We don't report vulnerabilities based on static analysis alone. Each finding is verified by actually exploiting it:
- For DoS bugs: measuring CPU usage, memory consumption, and process crashes
- For information disclosure: extracting and decoding the leaked data
- For authorization bypasses: demonstrating access to protected resources
Without a sandbox environment, our agent can still verify the existence and exploitability of a vulnerability with no code execution or test cases with near-zero false-positive rate. This is a recent breakthrough we had internally. An engineering blog on this quasi formal verification approach will be up soon!
If Winfunc can't exploit it, it doesn't report it.
We are firm believers in the motto PoC||GTFO. The agent too.
Implications
For Defenders
If AI can find 0-days in Node.js and React, it can find them in your code too. This changes the calculus:
-
Attack surface matters more: Every line of code that processes untrusted input is a potential vulnerability. AI systems can analyze codebases at a scale humans cannot.
-
Continuous security becomes essential: Point-in-time penetration tests leave gaps. As your code changes, new vulnerabilities emerge. AI-powered continuous scanning changes what's possible.
-
The vulnerability disclosure window shrinks: When vulnerabilities can be found automatically, expect faster discovery by both security researchers and attackers.
For Attackers
This technology is dual-use. The same capabilities that enable defensive security research can be used offensively. The security community needs to grapple with this reality.
The mitigating factor is that defensive use is commercially viable: there's a market for selling security services to organizations that want to find vulnerabilities before attackers do. This creates incentives for the technology to be developed and deployed defensively.
Talking about markets, selling 0-day exploits is a good one, too. But let's just not get into that.
For the Industry
Security engineering is changing. The dichotomy between "dumb scanners" and "expensive human experts" is dissolving. AI systems occupy a new position: they have the scalability of automated tools and (increasingly) the judgment of human researchers.
This doesn't eliminate the need for human security expertise. Someone needs to build these systems, interpret their output, and handle the edge cases they can't. But it changes what human security work looks like.
Responsible Disclosure
Both vulnerabilities were responsibly disclosed to the respective security teams:
CVE-2026-21636 (Node.js)
- Reported to the Node.js security team
- Patched in Node.js 25.3.0, 24.13.0, 22.22.0, and 20.20.0
- Credited to mufeedvh in the security advisory
CVE-2026-23864 (React)
- Reported to Meta Bug Bounty and coordinated with the React team
- Patched in React 19.0.4, 19.1.5, and 19.2.4
- Credited to Mufeed VH from Winfunc Research, along with other reporters who independently discovered related issues
Both organizations handled the disclosures professionally and patched the issues promptly. Our experience with coordinated disclosure has been universally positive with major open-source projects.
Conclusion
In January 2026, an AI system found, exploited, and reported zero-day vulnerabilities in two of the most important pieces of JavaScript infrastructure. The vulnerabilities were real, the exploits worked, and the patches were necessary.
This is a capability milestone. Not because it's the first time AI has been used in security (vulnerability scanners have used machine learning for years), but because it represents a qualitative shift in what AI can do.
We built Winfunc to find the bugs that humans and traditional scanners miss. The Node.js and React vulnerabilities are proof of concept.
The same system that found these vulnerabilities has also found SQL injection in Supabase, YAML parsing issues in Bun (DoS), and authorization flaws in Gumroad, to list a few. The vulnerabilities span different languages, frameworks, and vulnerability classes. You can see some of our findings on our Hacktivity page.
If you're responsible for critical infrastructure and want to know what an AI-powered security audit would find in your codebase, reach out.
For more details on vulnerabilities we've discovered, see our Hacktivity page. For technical background on how our system works (albeit very outdated), see How Asterisk Works.
