CVE-2026-39315: 
JavaScript vulnerability analysis and mitigation

Overview

CVE-2026-39315 is a security feature bypass vulnerability in Unhead, a document head and template manager used by Nuxt.js applications. The flaw resides in the useHeadSafe() composable — explicitly recommended by Nuxt's documentation for safely rendering user-supplied content in <head> — where the hasDangerousProtocol() function can be bypassed using leading-zero padded HTML numeric character references. All versions of Unhead prior to 2.1.13 (for Node.js) are affected. The vulnerability was first reported to Vercel's HackerOne program on 2026-03-22, cross-reported to unhead maintainers on 2026-04-03, and publicly disclosed on 2026-04-09 with a fix released in version 2.1.13. It carries a CVSS v3.1 base score of 6.1 (Medium) (GitHub Advisory).

Technical details

The root cause is classified as CWE-184 (Incomplete List of Disallowed Inputs) and CWE-116 (Improper Encoding or Escaping of Output). In packages/unhead/src/plugins/safe.ts, the HTML entity decoder uses two regular expressions with fixed-width digit caps — &#x([0-9a-f]{1,6});? (max 6 hex digits) and &#(\d{1,7});? (max 7 decimal digits) — to decode entities before checking for blocked URI schemes (javascript:, data:, vbscript:). However, the HTML5 specification permits an unlimited number of leading zeros in numeric character references, so an attacker can supply a padded entity like &#0000000058; (10 decimal digits for :) or &#x000003A; (7 hex digits) that exceeds the regex cap. The decoder silently skips the oversized entity, the raw unvalidated string is passed to startsWith('javascript:') which returns false, and makeTagSafe() writes the value verbatim into SSR HTML output. The browser's native HTML parser then decodes the padded entity and reconstructs the blocked URI scheme. A detailed PoC with reproduction steps and payloads is publicly available in the GitHub security advisory (GitHub Advisory, Patch Commit).

Impact

Successful exploitation allows an unauthenticated attacker to inject javascript:, data:, or vbscript: URI schemes into server-rendered HTML <head> elements, bypassing the documented safety guarantees of useHeadSafe(). In applications where downstream code reads and processes <link> href values — such as head management utilities, SEO tooling, icon preview features, or iframe loaders — this results in confirmed cross-site scripting (XSS), enabling session token theft, cookie exfiltration, and redirection of users to malicious sites. The scope is changed (affecting the victim's browser context), with low confidentiality and integrity impact and no availability impact. The vulnerability is particularly impactful because it silently violates the security contract that Nuxt developers rely on when following official documentation (GitHub Advisory).

Exploitability

A public proof-of-concept exploit with detailed step-by-step reproduction instructions, concrete payloads, and a full working cookie-exfiltration demo is available in the GitHub security advisory (GitHub Advisory). The vulnerability requires no authentication and no special privileges, but does require user interaction (a victim must visit a page rendering attacker-controlled content). 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.048% (very low probability of exploitation in the near term). No threat actor attribution has been reported.

Exploitation steps

  1. Identify a target: Find a Nuxt application using Unhead < 2.1.13 that renders user-supplied content via useHeadSafe() in the document <head> (e.g., user-controlled link href or similar attributes).
  2. Craft a padded entity payload: Construct a URI that bypasses the regex digit cap. For example, use java&#0000000058;script:alert(1) (10-digit decimal padding, exceeds the \d{1,7} cap) or data&#x000003A;text/html,<script>alert(document.cookie)</script> (7-digit hex padding, exceeds the [0-9a-f]{1,6} cap).
  3. Inject the payload: Supply the crafted value as user input that will be passed to useHeadSafe() — for example, as a href value in a link tag: { rel: 'icon', href: 'data&#x000003A;text/html;<base64-payload>' }.
  4. Verify SSR output: Confirm the raw padded entity is written verbatim into the server-rendered HTML by inspecting the page source or running curl -s http://<target>/ | grep '<link'. The unvalidated value should appear in the SSR output.
  5. Trigger downstream execution: The browser's HTML parser decodes the padded entity natively, reconstructing the blocked URI. If any downstream code (head management utility, SEO script, icon preview feature) reads the href and loads it into an <iframe>, the data: URI executes arbitrary JavaScript — including cookie exfiltration via a beacon request to an attacker-controlled server (GitHub Advisory).

Indicators of compromise

  • Network: Outbound GET requests from victim browsers to unexpected external domains with query parameters containing encoded cookie values or document.cookie data; unusual beacon/image requests to webhook or attacker-controlled URLs originating from page load.
  • Logs: Server-side access logs showing requests with href or link attribute values containing patterns like &#000000 (many leading zeros in decimal entities) or &#x00000 (many leading zeros in hex entities) in user-supplied input fields.
  • File System / SSR Output: Presence of unescaped padded HTML entities (e.g., &#0000000058;, &#x000003A;) in server-rendered HTML <head> sections, particularly within <link> tags' href attributes.
  • Process/Application Behavior: Unexpected <iframe> elements dynamically appended to the DOM by head management or SEO scripts, loading data: or javascript: URIs derived from <link> tag href values (GitHub Advisory).

Mitigation and workarounds

Upgrade Unhead to version 2.1.13 or later, which fixes the vulnerability by removing the fixed digit caps from both entity-decoding regexes (changing {1,6} and {1,7} to +), ensuring all spec-compliant leading-zero padded entities are decoded before the scheme check runs (Patch Commit, Release v2.1.13). If an immediate upgrade is not possible, avoid using useHeadSafe() to render untrusted user-supplied content in the document head, or implement additional server-side HTML sanitization (e.g., stripping or rejecting numeric character references with excessive leading zeros) before passing content to the composable (GitHub Advisory).

Community reactions

The vulnerability was originally submitted to Vercel's HackerOne bug bounty program on 2026-03-22 but received no response after 12 days, prompting the researcher to cross-report directly to the unhead maintainers via GitHub private security advisory on 2026-04-03. The unhead maintainers responded promptly and released the fix in version 2.1.13. The advisory credits researcher cybe4sent1nel and notes this is a distinct issue from the prior CVE-2026-31860 (GHSA-g5xx-pwrp-g3fv), which targeted a different code path (GitHub Advisory).

Additional resources


Source: This report was generated using AI

Related JavaScript vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-966w-4vpf-p7hcHIGH7.1
  • JavaScript logoJavaScript
  • @aloma.io/aloma
NoYesOct 25, 2026
GHSA-mrwp-f3q8-3g9pMEDIUM5.9
  • JavaScript logoJavaScript
  • follow-redirects
NoYesOct 25, 2026
GHSA-hfm3-x63j-7fxpHIGHN/A
  • JavaScript logoJavaScript
  • @payload-auth-link/migrate
NoYesOct 25, 2026
GHSA-6244-vvv9-76f5MEDIUMN/A
  • JavaScript logoJavaScript
  • @payload-auth-link/plugin
NoYesOct 25, 2026
GHSA-q53q-qg98-p9jfHIGHN/A
  • JavaScript logoJavaScript
  • llm-fw
NoYesOct 25, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Additional Wiz resources

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management