
Cloud Vulnerability DB
A community-led vulnerabilities database
CVE-2026-31860 is a Cross-Site Scripting (XSS) vulnerability in Unhead, a document head and template manager used widely with Nuxt.js. The flaw allows the useHeadSafe() composable — specifically recommended by Nuxt documentation for safely handling user-generated content — to be bypassed, enabling injection of arbitrary HTML attributes including event handlers into SSR-rendered <head> tags. All versions of the unhead npm package up to and including 2.1.10 are affected; the issue was disclosed and patched on March 12, 2026. It carries a CVSS v3.1 score of 6.1 (Medium) and a CVSS v4.0 score of 5.3 (Medium) (Github Advisory, Unhead Advisory).
The root cause is CWE-79 (Improper Neutralization of Input During Web Page Generation). The vulnerable acceptDataAttrs function in safe.ts (lines 16–20) permits any object property key starting with data- to pass through to the final HTML output, checking only the prefix without validating whether the key contains spaces or other characters that break HTML attribute parsing. The propsToString function then interpolates these property keys directly into the HTML string without sanitization (attrs += value === true ? ${key}: ${key}="${encodeAttribute(value)}"), so a key like 'data-x onload=alert(document.domain) y'causes the browser to parseonload=alert(document.domain)as a separate, executable attribute. This injection applies to all tag types sinceacceptDataAttrsis merged into every tag's props. A secondary bypass involved case-sensitive protocol checks (e.g.,Javascript:bypassingjavascript:` detection) (Unhead Advisory, Github Advisory).
Successful exploitation allows an unauthenticated attacker to inject arbitrary JavaScript event handlers into server-side rendered HTML <head> tags, achieving stored XSS execution in every victim's browser that loads the affected page. The most reliable vector uses <link> tags with an onload handler that fires when a valid stylesheet loads, enabling session hijacking, credential theft, DOM manipulation, or redirection to malicious sites. The scope is changed (affecting the user's browser context beyond the vulnerable system), with low confidentiality and integrity impact on subsequent systems (Github Advisory, Unhead Advisory).
A proof-of-concept exploit with concrete payload examples is publicly available in the GitHub Security Advisory, demonstrating reliable XSS execution via crafted data-* attribute keys (Unhead Advisory). No authentication or special privileges are required; the attacker only needs the ability to supply user-generated content (e.g., SEO metadata, CMS fields) that is processed by useHeadSafe(). There is no evidence of in-the-wild exploitation at this time, and the vulnerability is not listed in the CISA KEV catalog. The EPSS score is approximately 0.054%, indicating a low near-term exploitation probability (Github Advisory).
useHeadSafe() for SSR rendering. Versions up to 2.1.10 are vulnerable.data-* property key containing a space followed by an event handler, such as:{ rel: 'stylesheet', href: '/valid-stylesheet.css', 'data-x onload=alert(document.domain) y': 'z' }useHeadSafe() passes the malicious key through acceptDataAttrs unchecked, producing HTML such as:<link rel="stylesheet" href="/valid-stylesheet.css" data-x onload=alert(document.domain) y="z">onload=alert(document.domain) as a standalone attribute; once the stylesheet loads, the handler fires, executing arbitrary JavaScript in the victim's browser context (Unhead Advisory, Github Advisory).data-* keys with embedded spaces or event handler strings (e.g., onload=, onclick=, onerror=).data- prefixed attribute names; application error logs related to unexpected attribute structures in head tag processing.<link>, <meta>, or other head tags with unexpected inline event handler attributes (e.g., onload=, onerror=) not present in application templates.<head> tags; unexpected JavaScript execution originating from <link> or <meta> elements in the page head (Unhead Advisory).Upgrade the unhead npm package to version 2.1.11 or later, which validates data-* attribute names using a strict regex (/^[a-z][a-z0-9\-]*[a-z0-9]$/i) to reject keys containing spaces or special characters, and also adds case-insensitive protocol checks and additional sanitization (Unhead Release, Patch Commit). If immediate patching is not possible, avoid using useHeadSafe() to process untrusted user-generated content, and implement server-side input validation that rejects property keys containing spaces or characters outside the set [a-zA-Z0-9-]. Deploying a strict Content Security Policy that disallows inline event handlers provides an additional layer of defense-in-depth.
The vulnerability was reported by security researcher simonkoeck and promptly addressed by Unhead maintainer harlan-zw, who released the fix in version 2.1.11 with 69 new edge-case tests covering attribute injection, protocol bypass, type coercion, and prototype pollution (Unhead Release). The advisory was noted in the Nuxt/Unhead community given that useHeadSafe() is the officially recommended composable for handling user-generated content, making the bypass particularly impactful for developers who trusted the API's safety guarantees. Coverage appeared on security aggregators and Bluesky shortly after disclosure (Github Advisory).
Source: This report was generated using AI
Free Vulnerability Assessment
Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.
Get a personalized demo
"Best User Experience I have ever seen, provides full visibility to cloud workloads."
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
"We know that if Wiz identifies something as critical, it actually is."