After my previous article about Critical Vulnerability in React Server Components (RSC), I decided to draft a test suite (Node.js + Jest + supertest) that programmatically attempts exploit-style requests against a local RSC server and flags vulnerability.
So here is a focused, ready-to-run Node.js + Jest + supertest test suite that performs controlled "exploit-style" payload injections against a local RSC endpoint. It does not contain any harmful exploit; instead, it validates whether your server safely rejects malformed Flight payloads.
This is suitable for local vulnerability checks only.
I. Project Setup
Assuming you have a local RSC-capable app (Next.js or custom RSC server) running on:
http://localhost:3000If your RSC endpoint differs, adjust the route.
Install test dependencies:
$ npm install --save-dev jest supertest
Create the Jest config (if you don’t already have one):
$ npx jest --init
Choose defaults. Make sure testEnvironment is node.
II. Example Directory Structure
my-rsc-test/
|--tests/
|--rsc-vuln.test.js
|--package.json
III. Test Suite:
In the tests/rsc-vuln.test.js
const request = require("supertest");
const BASE_URL = "http://localhost:3000";
// Replace this with your actual Flight/RSC endpoint.
// For Next.js 14–15+, this is usually:
// /_next/data/{build-id}/(server)/rsc
// or a framework-specific endpoint.
// For testing, you can expose a custom route or inspect your network tab.
const RSC_ENDPOINT = "/react";
describe("RSC Vulnerability Probe", () => {
test("Rejects malformed Flight payload", async () => {
const maliciousPayload = `
1:{"type":"malformed","data":"<?bad_payload>"}
2:INVALID
X:NOT_FLIGHT_FORMAT
`.trim();
const res = await request(BASE_URL)
.post(RSC_ENDPOINT)
.set("Content-Type", "text/x-component")
.send(maliciousPayload);
expect(res.status).not.toBe(200);
expect(res.text).not.toMatch(/executed|success|component/i);
});
test("Does NOT throw or execute arbitrary code paths", async () => {
const probePayload = `
1:{"$$typeof":"malicious_probe","cmd":"whoami"}
`.trim();
const res = await request(BASE_URL)
.post(RSC_ENDPOINT)
.set("Content-Type", "text/x-component")
.send(probePayload);
// A secure server usually:
// - returns 400
// - rejects the request
// - or crashes with a "bad RSC payload" error WITHOUT executing anything
expect([400, 404, 415, 500]).toContain(res.status);
// Ensure the server didn't echo or run anything
expect(res.text).not.toMatch(/root|user|whoami|cmd/i);
});
test("Server is not silently processing Flight-like module references", async () => {
const pseudoFlight = `
1:M1{"id":"malicious/module","name":"default"}
2:I1{"fake":"data"}
`.trim();
const res = await request(BASE_URL)
.post(RSC_ENDPOINT)
.set("Content-Type", "text/x-component")
.send(pseudoFlight);
// A vulnerable server may attempt to resolve module references
// A safe server should reject this immediately
expect(res.status).not.toBe(200);
expect(res.text).not.toMatch(/malicious\/module/);
});
});IV. Running the Test Suite
Start your RSC server in one terminal:
$ npm run dev
Run the tests:
$ npm testV. How to Interpret Results
Secure Server (expected)
Returns 400, 404, 415, or 500.
Never responds with:
successful component output
server-rendered markup
evidence that it parsed module references
echoed malicious content
Does not execute anything hinted inside payloads.
Possibly Vulnerable
Returns 200 or 2xx while accepting malformed payloads.
Outputs partial component rendering.
Attempts to resolve module references like:
malicious/moduleCrashes before rejecting the request (indicates unsafe parsing path).
Echoes interpreted data.
If any test signals suspicious behavior, upgrading to patched RSC packages is mandatory.
