Moderate severityOSV Advisory· Published Jan 15, 2026· Updated Jan 15, 2026
Svelte 5.46.0 - Hydratable Key Script-Breakout XSS (SSR)
CVE-2025-15265
Description
An SSR XSS exists in async hydration when attacker‑controlled keys are passed to hydratable. The key is embedded inside a <script> block without HTML‑safe escaping, allowing </script> to terminate the script and inject arbitrary JavaScript. This enables remote script execution in users' browsers, with potential for session theft and account compromise. This issue affects Svelte: from 5.46.0 before 5.46.3.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
sveltenpm | >= 5.46.0, < 5.46.4 | 5.46.4 |
Affected products
1Patches
1ef81048e2388Merge commit from fork
4 files changed · +30 −1
.changeset/tasty-vans-repeat.md+5 −0 added@@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: use `devalue.uneval` to serialize `hydratable` keys
packages/svelte/src/internal/server/renderer.js+2 −1 modified@@ -10,6 +10,7 @@ import { BLOCK_CLOSE, BLOCK_OPEN } from './hydration.js'; import { attributes } from './index.js'; import { get_render_context, with_render_context, init_render_context } from './render-context.js'; import { sha256 } from './crypto.js'; +import * as devalue from 'devalue'; /** @typedef {'head' | 'body'} RendererType */ /** @typedef {{ [key in RendererType]: string }} AccumulatedContent */ @@ -669,7 +670,7 @@ export class Renderer { for (const p of v.promises) await p; } - entries.push(`[${JSON.stringify(k)},${v.serialized}]`); + entries.push(`[${devalue.uneval(k)},${v.serialized}]`); } let prelude = `const h = (window.__svelte ??= {}).h ??= new Map();`;
packages/svelte/tests/runtime-runes/samples/hydratable-script-escape/_config.js+14 −0 added@@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + skip_no_async: true, + mode: ['hydrate'], + + props: { + key: '</script><script>throw new Error("pwned")</script>' + }, + + async test() { + // this test will fail when evaluating the `head` script if the vulnerability is present + } +});
packages/svelte/tests/runtime-runes/samples/hydratable-script-escape/main.svelte+9 −0 added@@ -0,0 +1,9 @@ +<script> + import { hydratable } from "svelte"; + + const { key } = $props(); + + const value = await hydratable(key, () => Promise.resolve('safe')); +</script> + +<p>{value}</p>
Vulnerability mechanics
Synthesis attempt was rejected by the grounding validator. Re-run pending.
References
6- fluidattacks.com/advisories/lydianghsathird-party-advisorypatchWEB
- github.com/advisories/GHSA-6738-r8g5-qwp3ghsaADVISORY
- github.com/sveltejs/svelte/security/advisories/GHSA-6738-r8g5-qwp3ghsavendor-advisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2025-15265ghsaADVISORY
- github.com/sveltejs/svelte/commit/ef81048e238844b729942441541d6dcfe6c8cccaghsaWEB
- github.com/sveltejs/svelte/releases/tag/svelte%405.46.4ghsaWEB
News mentions
0No linked articles in our index yet.