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
Locationheaders 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-routerv6 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
Locationheader 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+or6.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
Locationheaders 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
Locationheader 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+or6.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
Locationheaders for auth, tenant, invite, payment, and support flows. TRIAGE.mdwhen 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.