CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2025-15265
6.10.04%

Svelte 5 SSR XSS: When JSON.stringify Betrays You

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 18, 2026·5 min read·11 visits

PoC Available

Executive Summary (TL;DR)

Svelte 5 versions 5.46.0 through 5.46.2 are vulnerable to XSS during Server-Side Rendering. The framework uses unsafe JSON serialization for hydration keys, allowing attackers to break out of `<script>` tags using a `</script>` payload. Update to 5.46.3 immediately.

A classic 'breakout' vulnerability in Svelte 5's server-side rendering logic allows attackers to inject arbitrary JavaScript via the 'hydratable' function. By trusting 'JSON.stringify' to sanitize data embedded in HTML script tags, the framework inadvertently allows malicious payloads to terminate the script block and execute code in the victim's browser context.

The Hook: Svelte's Hydration Headache

Svelte 5 is the new hotness. It brought us 'runes', fine-grained reactivity, and a promise of better performance. But with great power comes great... complexity in the serialization layer. Specifically, we're looking at the Server-Side Rendering (SSR) mechanism. When you render a page on the server, the client needs to 'hydrate' that page—essentially waking up the static HTML and attaching JavaScript event listeners to it.

To do this, Svelte needs to pass data from the server to the client. It does this by embedding serialized data directly into the HTML, usually inside a <script> tag in the document head. This is a critical handover point. If the server messes up this game of 'telephone,' the client browser interprets the data as executable code rather than passive information.

CVE-2025-15265 is exactly that mess-up. It resides in the hydratable function, a feature used to persist state across the server-client boundary. The vulnerability isn't in your application code; it's deep inside how Svelte decides to write that data to the DOM. It's a classic case of trusting a standard library function (JSON.stringify) to do a security job it was never designed for.

The Flaw: The JSON vs. HTML Parsing War

Here is the fundamental rule of web security that developers forget once every generation: The HTML parser runs before the JavaScript parser.

When a browser receives an HTML document, it scans for tags. If it sees a <script> tag, it switches to 'script mode' until it sees the sequence </script>. The browser is dumb. It does not care if that closing tag is inside a JavaScript string, a comment, or a JSON object. If it sees </script>, it closes the block. Period.

Svelte's engineers made a fatal assumption. They assumed that if they ran JSON.stringify() on a key, it would be safe to drop into a script block.

// Ideally, this should happen:
var data = "<script>alert(1)</script>"; 
// Browser sees a string. Life is good.
 
// But if you are injecting it via server-side string concatenation:
<script>
  var data = "</script><script>alert(1)</script>";
</script>

In the vulnerable code, Svelte takes a user-controlled key, stringifies it, and dumps it right into the HTML. Because JSON.stringify does not escape the forward slash / or the less-than symbol < by default, a payload containing </script> successfully tells the browser: 'End the script here.' The text immediately following that—controlled by the attacker—is then rendered as raw HTML, allowing for a new malicious <script> tag to open.

The Code: The Smoking Gun

Let's look at the crime scene in packages/svelte/src/internal/server/renderer.js. The vulnerable logic was handling the serialization of entries for the hydration map.

The Vulnerable Code

// Svelte 5.46.0 - 5.46.2
// k is the key provided to hydratable()
// v is the value associated with it
entries.push(`[${JSON.stringify(k)},${v.serialized}]`);

See that JSON.stringify(k)? That's the kill shot. If k is the string "</script>", the output becomes ["</script>", .... The browser reads the HTML, hits that closing tag inside the string, and terminates the script context immediately.

The Fix (v5.46.3)

The Svelte team, credited to the discovery by Camilo Vera, replaced the native JSON serializer with devalue.uneval. The devalue library is specifically designed to emit JavaScript that is safe to embed in HTML.

// Fixed in 5.46.3
import * as devalue from 'devalue';
 
// ...
entries.push(`[${devalue.uneval(k)},${v.serialized}]`);

devalue.uneval turns < into \u003C and / into \u002F (or similar escapes) ensuring the browser never sees the literal sequence </script>.

The Exploit: Breaking Out of the Box

Exploiting this is trivially easy if you can control the key passed to hydratable. Imagine a scenario where a Svelte app uses a URL parameter or a search query as a hydration key.

The Setup

<!-- main.svelte -->
<script>
    import { hydratable } from "svelte";
    // 'key' comes from user input (e.g., URL param)
    let { key } = $props(); 
    
    // The vulnerability triggers here during SSR
    hydratable(key, () => { ... });
</script>

The Attack

An attacker sends a link to the victim: https://vulnerable-app.com/?key=</script><script>alert(document.cookie)</script>

  1. Server receives request: key is </script><script>alert(document.cookie)</script>.
  2. Serialization: Svelte runs JSON.stringify(key). Result: "\"</script><script>alert(document.cookie)</script>\"".
  3. Injection: The server constructs the HTML response:
<script>
  const h = (window.__svelte ??= {}).h ??= new Map();
  // The injection happens inside this array structure
  h.set(["</script><script>alert(document.cookie)</script>", ...]);
</script>
  1. Execution:
    • The browser executes the script until it sees </script> inside the string.
    • It closes the hydration script block (causing a syntax error in the JS, but who cares? We are already out).
    • It immediately parses <script>alert(document.cookie)</script> as a new script block.
    • BOOM: Code execution.

The Mitigation: Patch or Perish

The remediation path is straightforward: Update Svelte immediately.

Fixed Version: 5.46.3

If you are stuck on a vulnerable version for some god-forsaken reason (enterprise change freezes, am I right?), you technically could sanitize the input before passing it to hydratable, but that is a losing game. You will miss edge cases.

> [!NOTE] > Content Security Policy (CSP) > A strict CSP is your best safety net here. If your policy forbids inline scripts (script-src 'self'), this attack fails because the injected script block is inline and unsigned. However, Svelte apps often rely on inline scripts for hydration bootstrapping, so ensuring your CSP is configured correctly (using nonces or hashes) is critical.

Takeaway for Developers: Never assume JSON.stringify makes data safe for HTML embedding. It makes data safe for JavaScript contexts, but HTML context is a different beast entirely. Use libraries like devalue or serialize-javascript that explicitly handle HTML entity escaping.

Official Patches

SvelteGitHub Commit fixing the issue

Fix Analysis (1)

Technical Appendix

CVSS Score
6.1/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
EPSS Probability
0.04%
Top 100% most exploited

Affected Systems

Svelte Framework

Affected Versions Detail

Product
Affected Versions
Fixed Version
Svelte
Svelte
>= 5.46.0, < 5.46.35.46.3
AttributeDetail
CWE IDCWE-79
Attack VectorNetwork
CVSS Score6.1 (Medium)
ImpactCross-Site Scripting (XSS)
Vulnerable Componentserver/renderer.js (hydratable)
Exploit StatusPoC Available

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1059.007Command and Scripting Interpreter: JavaScript
Execution
CWE-79
Cross-site Scripting

Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

Known Exploits & Detection

Fluid AttacksOriginal advisory containing the PoC payload

Vulnerability Timeline

Vulnerability Discovered by Camilo Vera
2026-01-15
Patch Released in Svelte 5.46.3
2026-01-15
GHSA-6738-r8g5-qwp3 Published
2026-01-15

References & Sources

  • [1]GitHub Security Advisory
  • [2]Fluid Attacks Research Advisory

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.