VDB
KO
LOW

GHSA-m3q2-p4fw-w38m

Cross-site scripting via <NoScript> slot content in Nuxt's head components

Details

### 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 writes it to `textContent` rather than `innerHTML`. Slot content is now rendered as text; intentional markup inside `<NoScript>` is no longer parsed as HTML.

### Workarounds

Until you can upgrade:

- Do not interpolate untrusted input into `<NoScript>` slots. Replace `<NoScript>{{ x }}</NoScript>` with a static string, or sanitise / HTML-escape `x` at the source. - If you must render dynamic noscript content, write the tag yourself via `useHead({ noscript: [{ textContent: escapedValue }] })` after escaping `escapedValue`.

### Credit

Reported to Anthropic's coordinated vulnerability disclosure pipeline by Claude (Anthropic's AI assistant) and triaged by the Anthropic security team. Reference: ANT-2026-4NJYDFFM.

Independently reported by [@alcls01111](https://github.com/alcls01111) via GitHub's coordinated disclosure flow (`GHSA-8grp-wcq9-925q`), closed as a duplicate of this advisory.

Are you affected?

Enter the version of the package you're using.

Affected packages

npm / nuxt
Introduced in: 4.0.0 Fixed in: 4.4.7
Fix npm install nuxt@4.4.7
npm / nuxt
Introduced in: 0 Fixed in: 3.21.7
Fix npm install nuxt@3.21.7

References