Feb 17, 2026·6 min read·12 visits
Svelte versions prior to 3.59.2 failed to escape user input bound to `<textarea>` elements during server-side rendering. This allowed attackers to close the textarea tag prematurely and inject malicious scripts that execute immediately upon page load. The fix involves wrapping the output in an escape function.
A high-severity Cross-Site Scripting (XSS) vulnerability was discovered in the Svelte framework's Server-Side Rendering (SSR) engine. By exploiting improper escaping in `bind:value` directives on `<textarea>` elements, attackers can break out of the HTML tag context and inject arbitrary JavaScript. This affects applications rendering Svelte components on the server (e.g., SvelteKit) prior to version 3.59.2.
We love Svelte. It's the framework that isn't a framework. It compiles your code away into tiny, efficient, imperative JavaScript. It promises to handle the heavy lifting, the reactivity, and—crucially—the security. We trust the compiler to sanitize our inputs because, frankly, writing document.createElement by hand in 2024 is a form of masochism reserved for people who enjoy writing assembly.
But here's the thing about Server-Side Rendering (SSR): it's not DOM manipulation. It is, at its core, sophisticated string concatenation. The Svelte compiler takes your components and turns them into a function that spits out a long HTML string to send to the browser. And whenever you are concatenating strings to build HTML, you are dancing on the edge of a volcano.
This vulnerability, living in the shadows of the <textarea> tag, is a reminder that even the smartest compilers can slip up on the most basic HTML rules. It's a classic case of "it works on my machine (client-side)" failing catastrophically when moved to the server.
To understand this bug, you have to understand how browsers parse HTML. Most input elements use the value attribute (e.g., <input value="...">). Attributes are easy; you quote them, you escape quotes, and you move on.
But <textarea> is a weird beast. It doesn't use a value attribute. Its value is the text content between the opening and closing tags. In HTML parsing terms, this is often treated as RCDATA (Raw Text). The browser generally doesn't parse markup inside a textarea... until it sees a closing tag.
The vulnerability lies in src/compiler/compile/render_ssr/handlers/Element.ts. When Svelte compiled a component with <textarea bind:value={userInput}> for SSR, it essentially generated code that said: "Print <textarea>, then print userInput, then print </textarea>."
Do you see the problem? It didn't sanitize userInput. It assumed that because it was inside a textarea, it was safe. But if userInput contains </textarea>, the browser stops parsing the textarea context immediately and treats everything following it as raw HTML. The compiler was locking the front door but leaving the keys under the mat.
Let's look at the actual compiler code. This is where the magic (and the mistake) happened. The compiler is written in TypeScript and generates JavaScript string templates.
The Vulnerable Code (Pre-3.59.2):
// src/compiler/compile/render_ssr/handlers/Element.ts
} else if (binding.name === 'value' && node.name === 'textarea') {
const snippet = expression.node;
// FATAL FLAW: The snippet is injected directly without escaping
node_contents = x`${snippet} || ""`;
}The variable node_contents is what eventually gets shoved between the <textarea> tags. The x literal tag function is just a helper for generating code. The crucial part is ${snippet} || "". It takes whatever variable you bound to the textarea and dumps it into the HTML string.
The Fix (Commit a31dec5):
// src/compiler/compile/render_ssr/handlers/Element.ts
} else if (binding.name === 'value' && node.name === 'textarea') {
const snippet = expression.node;
// FIX: Wrap the content in the @escape macro
node_contents = x`@escape(${snippet} || "")`;
}The fix is elegantly simple. They wrapped the expression in @escape(...). This internal Svelte function converts characters like < to < and > to >. So, if an attacker tries to inject </textarea>, it becomes </textarea>, which the browser safely renders as text inside the box rather than parsing it as a tag closer.
Exploiting this is trivial if you can control data that gets pre-rendered on the server. Imagine a user profile page where you can set a "Bio". This bio is rendered into a generic <textarea> so the user can edit it later.
The Setup:
<textarea bind:value={userBio}></textarea>sometext</textarea><script>alert('pwned')</script>The Execution: When the server renders this page, it blindly concatenates the strings. The HTML sent to the victim looks like this:
<textarea>sometext</textarea><script>alert('pwned')</script></textarea>The Browser's Perspective:
<textarea>: "Okay, I'm starting a text box."sometext: "Putting this in the text box."</textarea>: "Okay, closing the text box."<script>...: "Oh, a script tag! I should execute this immediately."</textarea>: "Weird floating closing tag. I'll ignore it or show it in the DOM."Boom. XSS. The script executes as soon as the HTML is parsed, allowing cookie theft, session hijacking, or redirection.
Since this is an SSR vulnerability, the XSS payload is delivered in the initial HTML document. This is often more dangerous than client-side reflected XSS because:
It breaks the trust model of the framework. Developers use Svelte specifically because they expect bind:value to be safe by default. This bug silently turned a standard feature into a security hole.
The remediation is straightforward, but mandatory.
1. Upgrade Svelte
If you are on version 3.x, you must upgrade to 3.59.2 or later. If you are already on Svelte 4 or 5, you are safe (the fix was carried forward). Check your package.json and package-lock.json.
npm update svelte
# Check version
npm list svelte2. Defensive Coding (The Paranoia approach) Even with the patch, it is good hygiene to treat all user input as radioactive. If you are rendering user content on the server, ensure you have input validation layers (like Zod or Joi) active before the data even reaches the component tree. Never rely solely on the view layer to sanitize your database's dirty secrets.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
svelte Svelte | >= 3.0.0, < 3.59.2 | 3.59.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 (Cross-Site Scripting) |
| Attack Vector | Network |
| CVSS | 7.5 (High) |
| Affected Component | Svelte SSR Compiler (Textarea Handler) |
| Impact | Code Execution (Browser Context) |
| Exploit Status | PoC Available |
OpenList version 4.2.3 and prior is vulnerable to an authorization bypass and metadata leakage. When configured with the Bleve search engine backend, OpenList fails to perform separator-aware path matching when validating tenant containment. This allows authenticated users to access sibling directories sharing similar name prefixes. Furthermore, the search backend returns unfiltered global result counts, leaking existence verification data of unauthorized files via side-channel analysis.
An authorization bypass vulnerability in OpenList version 4.2.3 and below allows authenticated users to read arbitrary files outside of their designated base directories due to an insecure path prefix check using Go's standard strings.HasPrefix function.
A security policy bypass vulnerability exists in the AWS API MCP Server (awslabs-aws-api-mcp-server) from version 0.2.13 through 1.3.46. When the server fails to load the read-only operations index during startup (due to transient network failures, file permission issues, or other exceptions), it logs a warning but continues running in an insecure, degraded state. Under this condition, the security policy engine fails open, silently skipping all subsequent security checks and consent prompts for the lifetime of the process. This permits unauthorized mutating AWS CLI commands to execute via indirect prompt injection attacks.
An incomplete escaping vulnerability in the npm package 'shescape' allows unauthenticated users to trigger dynamic shell expansions, absolute path disclosure, and command block break-outs on Unix and Windows systems.
A critical command injection vulnerability in the shescape npm library affects Windows systems when running shell commands using cmd.exe. The escaping function fails to neutralize parentheses, allowing attackers to close shell blocks and execute arbitrary commands.
An escaping bypass in the npm package shescape on Unix platforms utilizing the Dash shell can result in unauthorized home directory path disclosure. The vulnerability occurs when user input containing specific sequences is passed inside shell variable assignment contexts. Additionally, the patch addresses secondary security gaps related to Zsh extended globbing and Windows CMD command block breakouts.