{"id":"CVE-2026-56317","aliases":["GHSA-m3q2-p4fw-w38m"],"title":"Cross-site scripting via <NoScript> slot content in Nuxt's head components","summary":"Cross-site scripting via <NoScript> slot content in Nuxt's head components","severity":"low","cwe":["CWE-79"],"vendor":"nuxt","product":"nuxt","ecosystem":"npm","affected":["nuxt >= 4.0.0, < 4.4.7","nuxt < 3.21.7"],"patched":["nuxt 4.4.7","nuxt 3.21.7"],"published":"2026-06-16","updated":"2026-09-09","sourceUpdated":"2026-09-09T23:51:01Z","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-m3q2-p4fw-w38m","references":[{"url":"https://github.com/nuxt/nuxt/security/advisories/GHSA-m3q2-p4fw-w38m"},{"url":"https://github.com/nuxt/nuxt/commit/4b054e9d95f8daf366cb144b52782047c511a66e"},{"url":"https://github.com/nuxt/nuxt/commit/7fea9fd687f1dacbfb63db5fae5839896b017a0e"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-56317"},{"url":"https://www.vulncheck.com/advisories/nuxt-cross-site-scripting-via-noscript-component-slot-content"},{"url":"https://github.com/advisories/GHSA-m3q2-p4fw-w38m"}],"tags":["ghsa","npm"],"epss":0.00342,"epssPercentile":0.27798,"ingestedAt":"2026-09-10T00:26:24.579Z","slug":"CVE-2026-56317","body":"## Overview\n\n### Impact\n\nNuxt's globally registered `<NoScript>` component (from `@unhead/vue` head components, re-exported by Nuxt) wrote its default-slot content to the `innerHTML` of the `<noscript>` head tag, bypassing the HTML escaping that `{{ }}` interpolation normally applies in Vue templates.\n\nApplications that placed untrusted, attacker-controllable data inside a `<NoScript>` slot, for example:\n\n```vue\n<NoScript>{{ route.query.banner }}</NoScript>\n```\n\nwould emit that value unescaped inside `<noscript>` in the server-rendered HTML. With scripting enabled, the HTML parser treats `<noscript>` content in `<head>` under the \"in head noscript\" insertion mode: any tag other than `link`, `meta`, `noframes`, or `style` implicitly closes `<noscript>` and is re-processed in the head. A payload such as `<script>...</script>` therefore escapes the element and executes in the document context.\n\nSibling head components (`<Style>`, `<Title>`) were not affected because they already routed slot text through the safe `textContent` path.\n\n### Affected versions\n\nAll currently supported versions of `nuxt` that ship the `<NoScript>` global component.\n\n### Patches\n\nFixed in `nuxt@4.4.7` (commit [`4b054e9d`](https://github.com/nuxt/nuxt/commit/4b054e9d95f8daf366cb144b52782047c511a66e)) and backported to `nuxt@3.21.7` (commit [`7fea9fd6`](https://github.com/nuxt/nuxt/commit/7fea9fd687f1dacbfb63db5fae5839896b017a0e)). The fix escapes `<NoScript>` slot content with `escapeHtml` from `@vue/shared` and writes it to `textContent` rather than `innerHTML`. Slot content is now rendered as text; intentional markup inside `<NoScript>` is no longer parsed as HTML.\n\n### Workarounds\n\nUntil you can upgrade:\n\n- Do not interpolate untrusted input into `<NoScript>` slots. Replace `<NoScript>{{ x }}</NoScript>` with a static string, or sanitise / HTML-escape `x` at the source.\n- If you must render dynamic noscript content, write the tag yourself via `useHead({ noscript: [{ textContent: escapedValue }] })` after escaping `escapedValue`.\n\n### Credit\n\nReported to Anthropic's coordinated vulnerability disclosure pipeline by Claude (Anthropic's AI assistant) and triaged by the Anthropic security team. Reference: ANT-2026-4NJYDFFM.\n\nIndependently reported by [@alcls01111](https://github.com/alcls01111) via GitHub's coordinated disclosure flow (`GHSA-8grp-wcq9-925q`), closed as a duplicate of this advisory.\n\n## Affected packages\n\n- `nuxt >= 4.0.0, < 4.4.7`\n- `nuxt < 3.21.7`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `nuxt 4.4.7`\n- `nuxt 3.21.7`","depth":"sunlit","depthScore":14,"depthScoreParts":{"impact":13.8,"likelihood":0.1,"exploitation":0,"ransomware":0},"changes":[]}