---
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.24992
ingestedAt: '2026-09-10T00:26:24.579Z'
---

## Overview

### 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.

## Affected packages

- `nuxt >= 4.0.0, < 4.4.7`
- `nuxt < 3.21.7`

## Remediation

Upgrade to a patched release:

- `nuxt 4.4.7`
- `nuxt 3.21.7`
