CVE-2026-41067 — Astro: XSS in define:vars via incomplete </script> tag sanitization · VulnScope
tag sanitization","datePublished":"2026-04-21T20:39:49.000Z","dateModified":"2026-05-05T16:07:54.660Z","description":"## Summary\n\nThe `defineScriptVars` function in Astro's server-side rendering pipeline uses a case-sensitive regex `/<\\/script>/g` to sanitize values injected into inline ``, ``, or `` and inject arbitrary HTML/JavaScript.\n\n## Details\n\nThe vulnerable function is `defineScriptVars` at `packages/astro/src/runtime/server/render/util.ts:42-53`:\n\n```typescript\nexport function defineScriptVars(vars: Record) {\n\tlet output = '';\n\tfor (const [key, value] of Object.entries(vars)) {\n\t\toutput += `const ${toIdent(key)} = ${JSON.stringify(value)?.replace(\n\t\t\t/<\\/script>/g, // ← Case-sensitive, exact match only\n\t\t\t'\\\\x3C/script>',\n\t\t)};\\n`;\n\t}\n\treturn markHTMLString(output);\n}\n```\n\nThis function is called from `renderElement` at `util.ts:172-174` when a ``, ``, `` — HTML tag names are case-insensitive but the regex has no `i` flag.\n2. **Whitespace before `>`**: ``, ``, `` — after the tag name, the HTML tokenizer enters the \"before attribute name\" state on ASCII whitespace.\n3. **Self-closing slash**: `` — the tokenizer enters \"self-closing start tag\" state on `/`.\n\n`JSON.stringify()` does not escape `<`, `>`, or `/` characters, so all these payloads pass through serialization unchanged.\n\n**Execution flow:** User-controlled input (e.g., `Astro.url.searchParams`) → assigned to a variable → passed via `define:vars` on a `\n