GHSA-m3q2-p4fw-w38m

Updated on 16 Jun 2026

Severity

Awaiting Analysis

Details

Overview

About vulnerability

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 &#123;&#123; &#125;&#125; interpolation normally applies in Vue templates.

Applications that placed untrusted, attacker-controllable data inside a <NoScript> slot, for example:

<NoScript>&#123;&#123; route.query.banner &#125;&#125;</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 [email protected] (commit 4b054e9d) and backported to [email protected] (commit 7fea9fd6). 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>&#123;&#123; x &#125;&#125;</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 via GitHub’s coordinated disclosure flow (GHSA-8grp-wcq9-925q), closed as a duplicate of this advisory.

Details

Affected product:
cli , nuxt
Affected packages:
nuxt-babel-preset-app @ 2.18.1 (+59 more)

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 &#123;&#123; &#125;&#125; interpolation normally applies in Vue templates.

Applications that placed untrusted, attacker-controllable data inside a <NoScript> slot, for example:

<NoScript>&#123;&#123; route.query.banner &#125;&#125;</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 [email protected] (commit 4b054e9d) and backported to [email protected] (commit 7fea9fd6). 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>&#123;&#123; x &#125;&#125;</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 via GitHub’s coordinated disclosure flow (GHSA-8grp-wcq9-925q), closed as a duplicate of this advisory.