Feb 26, 2026·6 min read·40 visits
Svelte 5's SSR error handling failed to escape `-->` sequences when serializing errors into HTML comments. Attackers can trigger an error containing malicious payloads to break out of the comment and execute XSS. Fixed in 5.53.5.
A Cross-Site Scripting (XSS) vulnerability exists in Svelte 5 versions prior to 5.53.5. The flaw occurs during Server-Side Rendering (SSR) when the framework attempts to serialize error objects into HTML comments for client-side hydration. Because the serialization process relied solely on `JSON.stringify()` without escaping HTML comment delimiters, an attacker can inject a closing comment tag (`-->`) to break out of the comment context and execute arbitrary JavaScript in the victim's browser.
Modern web frameworks have a love-hate relationship with the DOM. To make pages load fast, we use Server-Side Rendering (SSR) to spit out a full HTML page before the JavaScript bundle even wakes up. But once the JavaScript loads, it needs to 'hydrate' that static HTML—attach event listeners, build the virtual DOM, and figure out the state of the world.
Svelte 5, with its fancy new 'runes' system, handles this by embedding serialization markers directly into the HTML. When a component crashes during SSR (inside an error boundary), Svelte needs to tell the client: "Hey, something went wrong here, don't try to hydrate this part normally." To do this, it serializes the error object and stuffs it into an HTML comment. It's a clever trick—browsers ignore comments, so the layout doesn't shift until Svelte takes over.
But here's the problem with clever tricks: they often rely on assumptions. Svelte assumed that JSON.stringify() was safe enough to put inside an HTML comment. They forgot that the HTML parser and the JSON parser speak two very different languages, and in the gap between them, XSS lives.
This vulnerability is a classic case of "Context Confusion." In the world of JSON, the characters < and > are just boring string literals. JSON.stringify({ "msg": "-->" }) returns {"msg":"-->"}. It's valid JSON. It's safe JSON.
However, in the brutalist architecture of HTML, the sequence --> is the End of Comment delimiter. It doesn't matter if it's inside quotes, inside brackets, or inside a JSON object. If the HTML parser is reading a comment and sees -->, the comment ends. Immediately. Right there.
So, when Svelte takes that valid JSON and drops it into <!-- [JSON] -->, the browser parses it until it hits the attacker's -->. The rest of the JSON string is then dumped into the DOM as raw, executable markup. The developer trusted JSON.stringify to sanitize data, but JSON.stringify isn't an HTML sanitizer. It protects against JavaScript syntax errors, not HTML structure injection.
Let's look at the crime scene in Renderer.js. The vulnerable code was deceptively simple. It takes a transformed error object and pushes it into the output buffer wrapped in comments.
Vulnerable Code (Before):
// Inside the renderer logic
child.#out.push(`<!--${HYDRATION_START_FAILED}${JSON.stringify(transformed)}-->`);See the issue? It's a straight template literal injection. If transformed contains -->, the comment breaks. The fix, implemented in version 5.53.5, acknowledges that we are crossing a boundary between data and markup. We can't just stringify; we must escape the delimiters.
Fixed Code (After):
static #serialize_failed_boundary(error) {
var json = JSON.stringify(error);
// Manually escape angle brackets to their unicode equivalents
var escaped = json.replace(/>/g, '\\u003e').replace(/</g, '\\u003c');
return `<!--${HYDRATION_START_FAILED}${escaped}-->`;
}The fix is elegant. By converting < and > to \u003c and \u003e, the JSON remains valid (JSON parsers decode unicode escapes automatically), but the HTML parser no longer sees the structural characters that define tags or comments.
To exploit this, we need a specific setup: a Svelte 5 application using SSR, an Error Boundary, and a way to force an error that contains user-controlled input. Imagine a blog engine where a user can define a custom title that gets processed by a component.
The Attack Chain:
--> <script>alert(origin)</script> <!--.<!--{"message":"--> <script>alert(origin)</script> <!--"}-->.Here is how the browser sees the payload:
The trailing <!-- in the payload cleans up the mess, turning the real closing }--> of the JSON into a harmless comment, preventing syntax errors that might alert the user (or the console logs) too early.
This isn't just a client-side DOM XSS. This is Reflected XSS delivered via the initial server response. This distinction matters for a few reasons. First, it bypasses many client-side XSS filters that only look for malicious DOM manipulation after load. Second, because the payload arrives in the initial HTML document, it executes immediately—often before any client-side security frameworks or Content Security Policy (CSP) nonces might be fully hydrated or applied if they rely on JS to initialize (though a strict HTTP-header CSP would still block inline scripts).
If the application is an Admin Dashboard or a Social Platform using Svelte 5, this allows full account takeover. The attacker can steal HttpOnly-flagged cookies (if the XSS is used to proxy requests), read local storage, or perform actions as the victim. Given Svelte's popularity in modern, high-interactivity web apps, the attack surface is specific but high-value.
The remediation is straightforward: Update to Svelte 5.53.5 immediately. The Svelte team has patched the Renderer.js logic to handle the escaping natively.
If you cannot update (perhaps you are locked to a specific version for enterprise reasons), you must ensure that any custom error transformation logic sanitizes the input before Svelte sees it. However, this is risky. You would need to implement a transformError hook that recursively strips or escapes --> sequences from error messages. But let's be honest: you're going to miss an edge case. Just update the package.
> [!NOTE] > This vulnerability only affects apps using Server-Side Rendering (SSR). If you are building a pure Single Page App (SPA) where the backend only serves JSON APIs and the frontend is a static bundle, this specific injection path does not exist, as the DOM API used by the browser to create comments is not susceptible to delimiter collision in the same way raw HTML parsing is.
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:P/VC:L/VI:N/VA:N/SC:H/SI:H/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Svelte Svelte | >= 5.53.0, < 5.53.5 | 5.53.5 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network |
| CVSS Score | 5.3 (Medium) |
| Impact | Cross-Site Scripting (XSS) |
| Exploit Status | Proof of Concept (PoC) Available |
| Patch Status | Fixed in 5.53.5 |
A state persistence vulnerability exists in Tornado's CurlAsyncHTTPClient component where pooled pycurl.Curl handles are reused across asynchronous requests without a complete state reset. Consequently, sensitive per-request configurations, such as client TLS certificates or proxy basic authentication credentials, persist on the shared handle. This behavior leads to subsequent requests leaking these credentials to unauthorized remote servers.
CVE-2026-48748 is a denial-of-service vulnerability in Netty's HTTP/3 codec (netty-codec-http3) occurring when QPACK dynamic tables are enabled but the blocked streams limit is not explicitly configured. A bug in limit checking and a memory leak in stream tracking allow unauthenticated remote attackers to exhaust the JVM heap memory and crash the server.
CVE-2026-50009 is a cryptographic design vulnerability in the Netty network application framework. Prior to version 4.2.15.Final, the framework's QUIC protocol implementation fails to cryptographically segregate the generated Connection IDs and the associated Stateless Reset Tokens. An on-path network attacker who sniffs traffic during a Connection ID rotation can extract secret token material from cleartext headers, enabling them to inject spoofed reset packets and terminate active connections.
A critical hostname verification bypass vulnerability exists in the Netty network application framework when configured as a TLS client. When a developer registers a custom plain X509TrustManager, Netty wraps it inside an X509TrustManagerWrapper to adapt it to the X509ExtendedTrustManager API. However, this wrapper discards the SSLEngine context, bypassing critical hostname checks. Because the wrapper is identified as an X509ExtendedTrustManager, standard cryptographic engines and Netty's OpenSSL wrappers do not re-wrap it, failing to execute any hostname validation. Consequently, clients silently accept certificates for any host, enabling unauthenticated Man-in-the-Middle (MitM) attacks.
An uncontrolled resource pre-allocation flaw in the Netty Redis codec module allows remote unauthenticated attackers to cause a denial of service (OutOfMemoryError) by sending a crafted Redis Serialization Protocol (RESP) array header.
CVE-2026-50020 is a medium-severity HTTP Request Smuggling/Response Smuggling vulnerability (CWE-444) within the Netty asynchronous network application framework. The flaw resides in Netty's HTTP codec implementation, specifically the HttpObjectDecoder class, which silently consumes arbitrary ISO control bytes preceding the first request line.