CVE-2026-21884
High · 8.2React Router SSR XSS in ScrollRestoration
CVSS
8.2
EPSS
0.5%
Published
Jan 8, 2026
CISA due date
—
Cloudanix analysis
Some React Router websites can accidentally include attacker-supplied code in pages they generate on the server, allowing that code to run in visitors’ browsers.
- Exploitation
- Requires User Interaction
- Attacker needs
- User Interaction
- Complexity
- Moderate
- Impact
- Remote Code Execution
- Component
- Web Framework
- Class
- XSS
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
This is a cross-site scripting flaw in React Router Framework Mode applications that use server-side rendering and the <ScrollRestoration> API with getKey and/or storageKey values derived from untrusted input. During SSR, attacker-controlled key material can be embedded into the generated response in a way that allows JavaScript injection. Successful exploitation causes attacker-supplied script to execute in the victim user’s browser in the security context of the affected application. Applications are not affected if SSR is disabled, if React Router is used in Declarative Mode with <BrowserRouter>, or if it is used in Data Mode with createBrowserRouter/<RouterProvider>.
Why it matters to the business
An attacker who can influence the values used for scroll restoration keys may be able to run JavaScript in users’ browsers, which can lead to account takeover, session theft where tokens are browser-accessible, fraudulent actions performed as the user, phishing inside the trusted application, or unauthorized access to sensitive data displayed in the page. The issue has a high CVSS score, but it is not currently listed in CISA KEV, is not known to be used in ransomware campaigns, and has a low EPSS score, so urgency should be based primarily on whether the application uses the affected React Router mode and vulnerable props with untrusted data.
How an attack unfolds
An attacker first identifies a React Router Framework Mode application that performs server-side rendering and includes <ScrollRestoration>. The attacker then finds a route, parameter, slug, header-derived value, stored profile field, CMS entry, or other user-controllable data source that is used directly or indirectly to build the getKey return value or storageKey prop. The attacker supplies a payload crafted to break out of the intended JavaScript or HTML context in the SSR response. When the server renders the page, the malicious value is included in the generated markup or inline script. A victim who visits the affected page receives the poisoned server-rendered response, and the browser executes the injected JavaScript in the origin of the vulnerable application. From there, the attacker can read accessible page data, invoke application APIs as the victim, alter page content, or redirect the user to credential-harvesting flows. There are no named threat actors or public mature exploit campaigns identified from the provided data.
How to fix it
Upgrade React Router and related framework packages to a vendor-patched release when available for the application’s version line; no exact fixed package versions were provided in the input, so teams should consult the official React Router advisory and ensure lockfiles resolve to patched versions. In addition, review all uses of <ScrollRestoration> in Framework Mode SSR and ensure getKey and storageKey are not derived from untrusted content. Prefer static storageKey values and deterministic getKey outputs based only on trusted route metadata. If untrusted data must be involved, strictly validate it against a narrow allowlist such as alphanumeric, underscore, dash, and bounded length, and ensure output is safely encoded for its render context. Remove custom getKey/storageKey usage where it is not required. As a temporary mitigation, disable server-side rendering for affected routes or applications if operationally acceptable, or move away from the affected SSR Framework Mode pattern. Applications using Declarative Mode, Data Mode, or Framework Mode with SSR disabled should document why they are not exposed.
How to confirm the fix worked
Confirm exposure by searching the codebase for <ScrollRestoration> usage and checking whether the application is in React Router Framework Mode with SSR enabled. For each occurrence, determine whether getKey or storageKey is present and whether either value can be influenced by route params, query strings, request headers, cookies, CMS content, database content, localization files, or user-controlled profile data. Validate remediation by confirming dependency resolution uses a patched React Router version once published, rebuilding the application, and inspecting the generated SSR HTML for representative malicious key values to ensure payloads are encoded as inert data rather than executable script. Dynamic testing should include payloads containing script-breaking sequences, quotes, angle brackets, and event handlers in every input that can influence the key. A fixed or non-exposed application should either not render the affected pattern, should render sanitized key material only, or should encode injected test strings so they do not execute.
Typical attack path
- Identify a React Router application using Framework Mode with server-side rendering enabled.
- Confirm the rendered page includes <ScrollRestoration> behavior that uses getKey and/or storageKey.
- Find an input source that influences getKey or storageKey, such as a route parameter, query string, stored content field, localization value, tenant slug, or user profile value.
- Submit or store a payload that escapes the expected key context and injects JavaScript.
- Trigger SSR for the affected route so the payload is embedded into the server-rendered response.
- Convince or wait for a victim user to load the affected page.
- Execute attacker-controlled JavaScript in the victim’s browser under the affected application’s origin.
- Use the injected script to steal accessible data, perform actions as the victim, modify the UI, or redirect the user.
How to detect it
To determine whether exploitation already occurred, review logs for inputs containing XSS payloads submitted to routes or fields that may influence scroll restoration keys. Useful sources include CDN and WAF logs, reverse proxy access logs, application request logs, SSR rendering error logs, client-side error telemetry, security event logs, and audit logs for changes to stored content that is later rendered through affected routes. Focus on requests containing script-breaking sequences, HTML tags, JavaScript URLs, event handler attributes, encoded angle brackets, encoded quotes, or payloads that appear in route parameters, query parameters, slugs, CMS fields, profile fields, or other externally controlled values. Correlate suspicious requests with subsequent victim page views, unusual authenticated API calls, privilege changes, token refresh activity, or client-side errors indicating malformed script execution. Because no public mature exploit or named campaign is identified from the provided data, detection should combine generic XSS payload hunting with application-specific tracing of data used by <ScrollRestoration> getKey/storageKey.
- <ScrollRestoration
- getKey=
- storageKey=
- </script><script
- %3C%2Fscript%3E%3Cscript
- "><script
- %22%3E%3Cscript
- '><script
- %27%3E%3Cscript
- onerror=
- onload=
- javascript:alert(
- document.cookie
- localStorage.getItem
- sessionStorage.getItem
- fetch('https://
- fetch("https://
- new Image().src
- eval(atob(
- String.fromCharCode(
What your security team should do
- Prioritize inventory of React Router Framework Mode applications that have server-side rendering enabled.
- Search for <ScrollRestoration> with getKey or storageKey and rank findings highest where values come from user-controllable or externally managed content.
- Upgrade React Router packages to the first patched release applicable to each application as soon as available, and verify lockfiles and deployed artifacts reflect the patched version.
- Apply compensating controls immediately by replacing dynamic key values with constants or strict allowlisted values.
- Add regression tests that render SSR responses with malicious key-like input and assert that no executable script is produced.
- Review content security policy; use nonces or hashes and avoid unsafe-inline where feasible to reduce XSS impact, while treating CSP as a defense-in-depth control rather than the fix.
- Check historical web, CDN, WAF, and application logs for XSS probing against routes that can influence scroll restoration keys.
- If suspicious payloads are found, investigate affected user sessions, browser-accessible tokens, privileged actions, and unusual API activity following the page views.
- Document non-exposure for applications using Declarative Mode, Data Mode, or Framework Mode with SSR disabled to avoid unnecessary remediation work.
The record
A XSS vulnerability exists in in React Router's `<ScrollRestoration>` API in [Framework Mode](https://reactrouter.com/start/modes#framework) when using the `getKey`/`storageKey` props during Server-Side Rendering which could allow arbitrary JavaScript execution during SSR if untrusted content is used to generate the keys. > [!NOTE] > This does not impact applications if developers have [disabled server-side rendering](https://reactrouter.com/how-to/spa) in Framework Mode, or if they are using [Declarative Mode](https://reactrouter.com/start/modes#declarative) (`<BrowserRouter>`) or [Data Mode](https://reactrouter.com/start/modes#data) (`createBrowserRouter`/`<RouterProvider>`).
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|---|---|---|
| npm | @remix-run/react | 0 | 2.17.3 |
| npm | react-router | 7.0.0 | 7.12.0 |
Related vulnerabilities
- GHSA-8v8x-cx79-35w7 React Router SSR XSS in ScrollRestoration Same vulnerability
- GHSA-3cgp-3xvw-98x8 React Router has XSS Vulnerability Also affects @remix-run/react
- CVE-2025-59057 React Router has XSS Vulnerability Also affects @remix-run/react
- CVE-2026-53663 React Router is a router for React. Also affects react-router
- GHSA-84g9-w2xq-vcv6 React Router: Potential CSRF via PUT/PATCH/DELETE document requests Also affects react-router
- GHSA-rxv8-25v2-qmq8 React Router vulnerable to Denial of Service via reflected user input in single-fetch Also affects react-router
- GHSA-8x6r-g9mw-2r78 React Router vulnerable to DoS via unbounded path expansion in __manifest endpoint Also affects react-router
- GHSA-49rj-9fvp-4h2h React Router's vendored turbo-stream v2 allows arbitrary constructor invocation via… Also affects react-router