Cross-site scripting via <NoScript> slot content in Nuxt's head components
Date: 2026-06
Affected: npm/nuxt, npm/nuxt
Attack vector: xss
Category: vulnerability-disclosure
Severity: Low
CWE: CWE-79

### Impact Nuxt'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. Applications that placed untrusted, attacker-controllable data inside a `<NoScript>` slot, for example: ```vue <NoScript>{{ route.query.banner }}</NoScript> ``` would 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. Sibling head components (`<Style>`, `<Title>`) were not affected because they already routed slot text through the safe `textContent` path. ### Affected versions All currently supported versions of `nuxt` that ship the `<NoScript>` global component. ### Patches Fixed 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 writ


Mitigations:

Architectural layers (MAESTRO):