CVE-2026-40181 - React Router protocol-relative open redirect

React Router can emit an external redirect when application code passes a same-origin-looking path that starts with // to redirect(). Browsers reinterpret that value as a protocol-relative URL, so weak pre-validation can turn return, next, callback, invite, or tenant-switching parameters into an open redirect.

The dependency upgrade is necessary, but the durable fix is a shared redirect validator that rejects protocol-relative URLs before any route returns a Location header.

When to use it

  • A repository uses React Router v6 or v7 server-side redirects in loaders, actions, framework routes, auth callbacks, onboarding, invite, payment, tenant-switching, or support flows.
  • Redirect inputs can come from query strings, forms, cookies, headers, identity-provider state, tenant config, browser state, or CMS/support links.
  • Existing validators allow //, backslash host confusion, encoded slash variants, absolute cross-origin URLs, or duplicated route-local checks.
  • You need a bounded PR or triage note that upgrades React Router and proves final Location headers are safe.

Inputs

  • Package manifests, lockfiles, route modules, redirect helpers, auth/OIDC/SAML callbacks, Dockerfiles, images, deployment artifacts, SBOMs, and generated dependency reports.
  • Redirect-bearing route inventory, trusted-origin allow-list, final Location emission points, temporary fixed landing-page containment, and operator rollout owners.
  • Available package install, route tests, unit tests, lint/typecheck, build, deployment render, SBOM, and dependency/security scans.

Affected versions

Package Vulnerable versions Fixed versions
react-router v7 >=7.0.0, <7.14.1 7.14.1+
react-router v6 >=6.7.0, <6.30.4 6.30.4+

React Router Declarative Mode (<BrowserRouter>) is not affected by this server-side redirect helper issue.

Indicator-of-exposure

  • The repository resolves a vulnerable react-router v6 or v7 version.
  • Server-side loaders, actions, framework routes, auth callbacks, onboarding flows, invite links, payment returns, tenant switching, or support flows call redirect() with values influenced by users, identity providers, tenants, or browser state.
  • Existing “same-origin” redirect validation accepts strings beginning with //, encoded slash variants, backslash host confusion, or absolute cross-origin URLs.
  • Redirect logic is duplicated across routes instead of routed through a shared validator.
  • Tests cover only benign relative paths and do not assert the final Location header for rejected values.

Quick checks:

rg -n "\"react-router\"|redirect\\(|redirectDocument\\(|returnTo|return_to|next=|callback|continue|redirect_uri|destination|safeRedirect|isSafeRedirect|Location|new URL" .
npm ls react-router
pnpm why react-router
yarn why react-router

Windows:

rg -n "\"react-router\"|redirect\(|redirectDocument\(|returnTo|return_to|next=|callback|continue|redirect_uri|destination|safeRedirect|isSafeRedirect|Location|new URL" .
npm ls react-router
pnpm why react-router
yarn why react-router

Remediation strategy

  • Upgrade React Router to 7.14.1+ or 6.30.4+, depending on the release line in use.
  • Refresh lockfiles, generated dependency reports, SBOMs, container layers, and deployment artifacts.
  • Centralize redirect validation before route code calls redirect().
  • Prefer same-origin relative paths that start with exactly one /.
  • Reject protocol-relative URLs, absolute URLs unless explicitly allowlisted, scriptable schemes, encoded control characters, backslash host variants, and double-encoded redirect values.
  • Add route tests that assert both accepted benign paths and rejected final Location headers for every redirect-bearing flow.
  • If upgrade is blocked, force untrusted redirect parameters to a fixed same-origin landing page until patched versions deploy.

The prompt

You are remediating CVE-2026-40181 / GHSA-2j2x-hqr9-3h42, a React Router open
redirect caused by `redirect()` values that start with `//` and are interpreted
by browsers as protocol-relative URLs. Produce exactly one output:

- A reviewer-ready PR/change request that upgrades React Router, proves whether
  server-side redirect helpers are exposed, centralizes redirect validation,
  adds regression tests, refreshes generated artifacts, and documents operator
  rollout actions, or
- TRIAGE.md if this repository does not control an affected React Router
  server-side redirect surface.

## Rules

- Scope only CVE-2026-40181 / GHSA-2j2x-hqr9-3h42 and directly related
  server-side redirect validation.
- Treat cookies, sessions, OAuth/SAML/OIDC state, invite tokens, tenant IDs,
  billing data, callback URLs, and browser telemetry as sensitive.
- Do not use real attacker-controlled domains in production, preview links,
  screenshots, analytics, or shared logs.
- Do not remove auth, CSRF, tenant, invite, billing, or identity-provider
  checks to make redirect tests pass.
- Do not auto-merge.

## Steps

1. Inventory every React Router dependency, release line, lockfile, workspace,
   Docker image, SBOM, and deployment artifact controlled by this repository.
2. Determine resolved versions. A target is vulnerable when React Router v7
   resolves to `>=7.0.0, <7.14.1` or v6 resolves to `>=6.7.0, <6.30.4`.
3. Determine whether server-side route code calls `redirect()` or equivalent
   helpers. Declarative Mode browser-only usage is not exposed to this CVE.
4. Inventory redirect inputs from query parameters, form bodies, headers,
   cookies, OAuth/SAML/OIDC state, invite links, tenant config, CMS content,
   payment callbacks, support links, and browser storage.
5. If the repository does not control an affected server-side redirect surface,
   stop with `TRIAGE.md` listing checked files, resolved versions, and why the
   affected helper is absent.
6. Upgrade React Router to `7.14.1+` or `6.30.4+`. Refresh package-manager
   locks, generated dependency reports, SBOMs, images, and deployment output.
7. Add or harden a shared redirect validator:
   - allow same-origin relative paths that start with exactly one `/`;
   - allow absolute URLs only through an owner-approved trusted-origin
     allowlist;
   - reject `//`, `\\`, mixed slash/backslash host forms, `javascript:`,
     `data:`, `vbscript:`, `file:`, encoded control characters, encoded slash
     variants, and double-encoded redirect targets;
   - normalize before validation and validate again immediately before emitting
     the final `Location` value.
8. Update every redirect-bearing route to use the shared validator, including
   auth callbacks, invite flows, tenant switching, onboarding, payment returns,
   and support links.
9. Add regression tests:
   - benign same-origin paths are allowed;
   - `//host/path` and encoded slash variants are rejected;
   - cross-origin absolute URLs are rejected unless allowlisted;
   - scriptable schemes are rejected;
   - the final `Location` header is a safe same-origin value after validation.
10. Add a PR body section named `CVE-2026-40181 operator actions` that states:
    - React Router versions before and after;
    - whether server-side `redirect()` helpers are used;
    - which redirect-bearing routes were reviewed;
    - what validator behavior changed;
    - which regression tests passed;
    - any temporary fixed landing-page containment still in place.
11. Run available validation: package install, route tests, unit tests,
    typecheck, lint, build, SBOM refresh, dependency/security scans, and
    deployment rendering.
12. Use PR title:
    `fix(sec): remediate CVE-2026-40181 in React Router redirects`.

## Stop conditions

- No controlled deployable app resolves an affected React Router version.
- React Router is used only in browser-only Declarative Mode.
- Redirect behavior is owned by another package, platform, or vendor outside
  repository ownership.
- A safe fix requires broader auth or routing redesign; document the owner,
  target fixed version, and temporary fixed landing-page containment.
- Meaningful validation would require production sessions, live identity
  provider callbacks, customer URLs, or sensitive logs.
- Validation fails for unrelated pre-existing reasons; document those failures
  instead of broadening scope.

Verification - what the reviewer looks for

  • No controlled package manifest, lockfile, image, SBOM, or dependency report resolves vulnerable React Router versions on an exposed server-side redirect path.
  • Redirect-bearing routes use one shared validator.
  • Tests reject protocol-relative, scriptable, cross-origin, encoded, and double-encoded redirect targets.
  • The final emitted Location header is checked, not only the pre-validation input.
  • Auth callbacks, tenant switching, invite flows, billing returns, and support links keep their existing security checks.

Output contract

  • Reviewer-ready PR upgrading React Router to 7.14.1+ or 6.30.4+ with refreshed locks, images, generated reports, SBOMs, and deployment output.
  • Shared redirect validator used by every server-side redirect-bearing route, rejecting protocol-relative, scriptable, cross-origin, encoded, and double-encoded targets unless explicitly allow-listed.
  • Regression tests asserting both accepted safe paths and rejected final Location headers for auth, tenant, invite, payment, and support flows.
  • TRIAGE.md when React Router is browser-only Declarative Mode or the server-side redirect surface is outside repository ownership.

Watch for

  • Treating this as a harmless open redirect when login, OAuth, SAML, tenant, or invite flows can chain through it.
  • Checking that a string starts with / while allowing //.
  • Validating once, then redirecting a decoded or normalized value later.
  • Fixing one route while another helper or route-local redirect remains duplicated.
  • Logging rejected redirect values that contain tokens or customer URLs.

References