Back to Blog
high SEVERITY8 min read

How CSRF bypass happens in React Router RSC mode and how to fix it

A high-severity CSRF bypass vulnerability (GHSA-qwww-vcr4-c8h2) in React Router's RSC (React Server Components) mode allowed attackers to execute actions before the framework returned a 400 response. This vulnerability affected React Router versions prior to 7.18.2 and 8.3.0, enabling cross-site request forgery attacks that could bypass standard CSRF protections in applications using RSC mode.

O
By Orbis AppSec
•Technically reviewed by Anupam Mediratta•Published August 21, 2026•Reviewed August 21, 2026

Answer Summary

The React Router RSC Mode CSRF Bypass (GHSA-qwww-vcr4-c8h2, CWE-352) is a high-severity vulnerability in React Router versions before 7.18.2 and 8.3.0 that allows attackers to execute server actions before the framework returns a 400 error response. The vulnerability occurs in RSC (React Server Components) mode where CSRF validation timing allows malicious cross-site requests to trigger actions. The fix upgrades react-router and react-router-dom to version 7.18.2, which properly validates CSRF tokens before action execution and includes an updated cookie parser (from 0.7.2 to 1.1.1) to strengthen request validation.

Vulnerability at a Glance

cweCWE-352 (Cross-Site Request Forgery)
fixUpgrade to React Router 7.18.2/8.3.0 with improved CSRF validation timing and cookie parsing
riskAttackers can execute unauthorized server actions via cross-site requests before CSRF validation completes
languageJavaScript/TypeScript (React)
root causeAction execution occurs before 400 response is returned in React Router's RSC mode
vulnerabilityCSRF Bypass in RSC Mode

Introduction

In a Go service with a React UI frontend, we discovered a high-severity CSRF bypass vulnerability in core/http/react-ui/bun.lock affecting React Router version 7.18.1. The vulnerability, tracked as GHSA-qwww-vcr4-c8h2, exists in React Router's RSC (React Server Components) mode where server actions could execute before CSRF validation completed and returned a 400 error response. This timing flaw created a window for attackers to bypass CSRF protections and execute unauthorized actions on behalf of authenticated users.

The vulnerable dependency chain was identified in the lock file:

"react-router": ["react-router@7.18.1", "", { 
  "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, 
  "peerDependencies": { "react": ">=18", "react-dom": ">=18" }
}]

This matters because modern React applications increasingly use RSC mode for server-side rendering and data fetching. Any application using React Router 7.18.1 or earlier in RSC mode was vulnerable to CSRF attacks that could manipulate user data, trigger state changes, or execute privileged operations—all without valid CSRF tokens.

The Vulnerability Explained

CSRF (Cross-Site Request Forgery) attacks exploit the browser's automatic inclusion of cookies in HTTP requests. In a typical CSRF attack, a malicious website tricks a victim's browser into making authenticated requests to a target application. Modern frameworks defend against this by requiring CSRF tokens that attackers cannot obtain.

However, React Router versions prior to 7.18.2 had a critical flaw in their RSC mode implementation: actions would begin execution before CSRF validation completed. Here's what the vulnerable code path looked like:

// Vulnerable flow in React Router 7.18.1
1. Request arrives with potentially invalid CSRF token
2. Action handler begins execution immediately
3. CSRF validation runs in parallel
4. If validation fails, 400 response is prepared
5. But action may have already completed by this point

The dependency on the older cookie package (version 0.7.2) compounded the issue:

"cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="]

Attack Scenario

Consider a React application using React Router 7.18.1 in RSC mode with a server action that updates user preferences:

// Server action in RSC mode (vulnerable)
export async function updateUserSettings(formData) {
  const userId = getCurrentUser();
  const theme = formData.get('theme');

  // This executes BEFORE CSRF validation completes!
  await database.updateUserTheme(userId, theme);

  return { success: true };
}

An attacker could craft a malicious page:

<form id="csrf-attack" action="https://victim-app.com/settings" method="POST">
  <input type="hidden" name="theme" value="attacker-controlled">
  <input type="hidden" name="_csrf" value="invalid-token">
</form>
<script>
  document.getElementById('csrf-attack').submit();
</script>

When a victim visits this page:

  1. The form submits to the victim's authenticated session
  2. React Router 7.18.1 begins executing updateUserSettings()
  3. The database update completes
  4. CSRF validation finally runs and fails
  5. A 400 response is returned—but the damage is done

The real-world impact is severe: attackers could modify user settings, trigger financial transactions, change passwords, or execute any action the application exposes through RSC server actions—all without valid CSRF tokens.

The Fix

The fix upgrades both react-router and react-router-dom to version 7.18.2, along with updating the cookie dependency from 0.7.2 to 1.1.1. Here's the specific change in core/http/react-ui/bun.lock:

Before (Vulnerable):

"react-router": ["react-router@7.18.1", "", { 
  "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, 
  "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, 
  "optionalPeers": ["react-dom"] 
}, "sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg=="]
"cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="]

After (Fixed):

"react-router": ["react-router@7.18.2", "", { 
  "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, 
  "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, 
  "optionalPeers": ["react-dom"] 
}, "sha512-[updated-hash]"]
"cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="]

The corresponding package.json changes enforce these versions:

"dependencies": {
  "react-router": "7.18.2",
  "react-router-dom": "7.18.2"
}

How This Solves the Problem

React Router 7.18.2 implements a critical timing fix in RSC mode:

// Fixed flow in React Router 7.18.2
1. Request arrives with CSRF token
2. CSRF validation runs FIRST and completes
3. If validation fails, immediately return 400
4. Action handler executes ONLY after validation passes
5. No race condition possible

The security improvement is concrete: CSRF validation now acts as a gate that must pass before any action code executes. The updated cookie package (1.1.1) also provides more robust cookie parsing, reducing the attack surface for cookie manipulation techniques that could bypass validation.

The fix was applied to two files:
- core/http/react-ui/bun.lock: Updates the dependency lock to enforce React Router 7.18.2 and cookie 1.1.1
- core/http/react-ui/package.json: Specifies exact versions to prevent accidental downgrades

This dual-file approach ensures both the declared dependencies and the resolved dependency tree are secure, preventing package managers from installing vulnerable versions.

Key Takeaways

  • React Router 7.18.1's RSC mode allowed action execution before CSRF validation completed, creating a race condition that attackers could exploit to bypass CSRF protections
  • The fix in version 7.18.2 reorders the execution flow so CSRF validation acts as a mandatory gate before any server action code runs
  • The cookie dependency upgrade from 0.7.2 to 1.1.1 strengthens cookie parsing and reduces additional attack vectors
  • This vulnerability demonstrates that timing bugs in security controls are just as dangerous as missing controls—even if validation eventually fails, damage can occur if the check happens too late
  • Applications using React Router in RSC mode should immediately upgrade to 7.18.2 or 8.3.0 and verify that CSRF tokens are properly configured for all state-changing server actions

How Orbis AppSec Detected This

  • Source: HTTP request to React Router RSC endpoints in core/http/react-ui
  • Sink: Server action execution in React Router 7.18.1 before CSRF validation completes
  • Missing control: Proper ordering of CSRF token validation before action execution in RSC mode
  • CWE: CWE-352 (Cross-Site Request Forgery)
  • Fix: Upgraded react-router and react-router-dom to version 7.18.2, which enforces CSRF validation before action execution, and updated cookie parser to 1.1.1

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

The React Router RSC Mode CSRF bypass (GHSA-qwww-vcr4-c8h2) demonstrates how timing vulnerabilities in security controls can be just as exploitable as missing controls entirely. By allowing server actions to execute before CSRF validation completed, React Router 7.18.1 created a window for attackers to bypass protections designed to prevent cross-site request forgery.

The fix in version 7.18.2 is straightforward but critical: it reorders the execution flow to ensure CSRF validation acts as a mandatory gate. Combined with the updated cookie parser, this upgrade eliminates the race condition and restores the intended security guarantees of RSC mode.

For developers working with React Router, this vulnerability highlights the importance of staying current with security patches and implementing defense-in-depth strategies. CSRF protection should never be your only line of defense—use SameSite cookies, validate request origins, and require additional verification for sensitive operations.

Most importantly, this case shows why proactive security scanning matters. The vulnerability existed in a dependency lock file, easily overlooked in manual code reviews but immediately detectable by automated tools. Regular dependency audits and automated security fixes can prevent these issues from reaching production.

Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #11644

Related Articles

critical

How origin validation bypass happens in Express.js and how to fix it

A `POST /changeData` route in `src/main/server/routes/index.js` guarded state-changing writes with an origin allowlist, but the guard was wrapped in an `if (origin && ...)` truthiness check. Any request that simply omitted both `Origin` and `Referer` — a one-line `curl` command, a local script, a background process — skipped validation entirely and modified application data. The fix removes the truthiness short-circuit so a *missing* header is now treated as a rejection, not a pass.

critical

How CSRF vulnerabilities happen in Node.js API clients and how to fix them

A critical CSRF vulnerability in `lib/client.js` allowed attackers to forge authenticated POST requests to `/remote-ssh/api/*` endpoints. The fix adds the `X-Requested-With: XMLHttpRequest` header to enable proper CSRF token validation, blocking malicious cross-site requests with a minimal one-line change.

high

How CSRF and Missing Authentication Protection Happens in Node.js Express Routes and How to Fix It

A critical vulnerability in code-server's `/mint-key` endpoint allowed unauthenticated cross-origin requests to generate or retrieve VS Code web server authentication keys. By adding the `ensureAuthenticated` middleware to the POST handler, the fix ensures only authenticated users can mint new keys, eliminating the CSRF attack vector.

high

How CSRF vulnerabilities happen in Express.js and how to fix them

A HIGH severity Cross-Site Request Forgery (CSRF) vulnerability was found in `integrationExamples/topics/topics-server.js`, an Express.js demo server that lacked any CSRF protection middleware. The file was deleted entirely after assessment determined it posed unnecessary risk to downstream consumers of this Node.js library.

high

How Cross-Site Request Forgery (CSRF) happens in Express.js and how to fix it

A semgrep audit flagged `devboard/server/index.js` for lacking any CSRF middleware, meaning every state-changing route (`POST`, `PUT`, `DELETE` under `/api/*`) could be triggered by a forged cross-origin request riding on a victim's session cookie. The fix wires in `cookie-parser` and `csurf` right after body parsing, so every mutating request now requires a valid, per-session CSRF token before it reaches route handlers.

critical

How OAuth CSRF Attacks Happen in Node.js and How to Fix Them

A missing OAuth state parameter validation in `src/account_manager.js` left the `startOAuthServer()` function vulnerable to CSRF attacks, allowing an attacker to inject their own authorization code into a victim's active OAuth session. The fix generates a cryptographically random state token using `crypto.randomBytes()`, returns it alongside the server handle, and rejects any callback where the returned state doesn't match — closing the attack window entirely. This affects all downstream consume