Cross-site scripting via <NoScript> slot content in Nuxt's head components
Published 16 Jun 2026 · Updated 10 Sept 2026
Affected packages
- Affected
- >=4.0.0 <4.4.7
- Fixed in
- 4.4.7
npm install nuxt@4.4.7- Affected
- <3.21.7
- Fixed in
- 3.21.7
npm install nuxt@3.21.7Details
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:
<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`) and backported to nuxt@3.21.7 (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>{{ x }}</NoScript>with a static string, or sanitise / HTML-escapexat the source. - If you must render dynamic noscript content, write the tag yourself via
useHead({ noscript: [{ textContent: escapedValue }] })after escapingescapedValue.
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.
Is GHSA-m3q2-p4fw-w38m in any of your client repos?
Checking one package by hand is fine. Checking it across forty client projects is not. NPMscan reads the lockfiles in every GitHub repo you pick, finds each project with an affected nuxt, and gives you the command that fixes it.
References
- Linkgithub.com/nuxt/nuxt/security/advisories/GHSA-m3q2-p4fw-w38m
- Advisorynvd.nist.gov/vuln/detail/CVE-2026-56317
- Linkgithub.com/nuxt/nuxt/commit/4b054e9d95f8daf366cb144b52782047c511a66e
- Linkgithub.com/nuxt/nuxt/commit/7fea9fd687f1dacbfb63db5fae5839896b017a0e
- Packagegithub.com/nuxt/nuxt
- Linkwww.vulncheck.com/advisories/nuxt-cross-site-scripting-via-noscript-component-slot-content
Advisory data from OSV.dev (opens OSV.dev in a new tab), refreshed daily.