Cross-site Scripting (XSS)
Description
The package svelte before 3.49.0 are vulnerable to Cross-site Scripting (XSS) due to improper input sanitization and to improper escape of attributes when using objects during SSR (Server-Side Rendering). Exploiting this vulnerability is possible via objects with a custom toString() function.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Svelte versions before 3.49.0 are vulnerable to cross-site scripting (XSS) during server-side rendering via objects with custom toString() functions.
The vulnerability arises from improper escaping of attribute values when Svelte components use objects during server-side rendering (SSR). Specifically, the escape_attribute_value function did not handle objects, allowing their toString() output to be inserted without proper escaping [1][2]. This leads to XSS.
Exploitation requires an attacker to control an object passed as a prop to a Svelte component that renders it as an attribute. For example, providing an object with a malicious toString() method that injects script tags [4]. No authentication is needed if the application accepts user input as component props.
Successful exploitation allows arbitrary JavaScript execution in the context of the user's browser, leading to session theft, data exfiltration, or other malicious actions [2].
The issue is fixed in Svelte version 3.49.0. Users should upgrade immediately [2][3]. No known public exploit at the time of disclosure, but the fix hardens attribute escaping.
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
sveltenpm | < 3.49.0 | 3.49.0 |
Affected products
2- svelte/sveltedescription
Patches
1f8605d6acbf6[fix] harden attribute escaping during ssr (#7530)
3 files changed · +23 −10
src/runtime/internal/ssr.ts+10 −8 modified@@ -85,18 +85,20 @@ export function escape(value: unknown, is_attr = false) { let escaped = ''; let last = 0; - while (pattern.test(str)) { - const i = pattern.lastIndex - 1; - const ch = str[i]; - escaped += str.substring(last, i) + (ch === '&' ? '&' : (ch === '"' ? '"' : '<')); - last = i + 1; - } + while (pattern.test(str)) { + const i = pattern.lastIndex - 1; + const ch = str[i]; + escaped += str.substring(last, i) + (ch === '&' ? '&' : (ch === '"' ? '"' : '<')); + last = i + 1; + } return escaped + str.substring(last); } export function escape_attribute_value(value) { - return typeof value === 'string' ? escape(value, true) : value; + // keep booleans, null, and undefined for the sake of `spread` + const should_escape = typeof value === 'string' || (value && typeof value === 'object'); + return should_escape ? escape(value, true) : value; } export function escape_object(obj) { @@ -192,7 +194,7 @@ export function create_ssr_component(fn) { export function add_attribute(name, value, boolean) { if (value == null || (boolean && !value)) return ''; - const assignment = (boolean && value === true) ? '' : `="${escape_attribute_value(value.toString())}"`; + const assignment = (boolean && value === true) ? '' : `="${escape(value, true)}"`; return ` ${name}${assignment}`; }
test/server-side-rendering/samples/attribute-escaped-quotes-spread/_expected.html+7 −1 modified@@ -2,4 +2,10 @@ bar="'></div><script>alert(42)</script>" foo=""></div><script>alert(42)</script>" qux="&&&" -></div> \ No newline at end of file + quux=""><script>alert(42)</script>" +></div> + +<div + foo="foo" + unsafe=""><script>alert(42)</script>" +></div>
test/server-side-rendering/samples/attribute-escaped-quotes-spread/main.svelte+6 −1 modified@@ -1,10 +1,15 @@ <script> + const safe = { foo: 'foo' }; + const unsafe = { toString: () => '"><script>alert(42)<\/script>' }; + export let props = { foo: '"></div><script>alert(42)</' + 'script>', bar: "'></div><script>alert(42)</" + 'script>', ['"></div><script>alert(42)</' + 'script>']: 'baz', qux: '&&&', + quux: unsafe }; </script> -<div {...props}></div> \ No newline at end of file +<div {...props}></div> +<div {...safe} {unsafe}></div>
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-wv8q-r932-8hc7ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-25875ghsaADVISORY
- github.com/sveltejs/svelte/commit/f8605d6acbf66976da9b4547f76e90e163899907ghsax_refsource_MISCWEB
- github.com/sveltejs/svelte/pull/7530ghsaWEB
- github.com/sveltejs/svelte/pull/7530%23issuecomment-1158575990mitrex_refsource_MISC
- snyk.io/vuln/SNYK-JS-SVELTE-2931080ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.