unjs/unhead · Security

Unhead Vulnerable to Bypass of URI Scheme Sanitization in makeTagSafe via Case-Sensitivity

GHSA ID
GHSA-5339-hvwr-7582
CVE ID
CVE-2026-31873
Severity
low
Published
Updated
CVSS
0 · CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N
CVSS v3
0 · CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N

Description

The link.href check in makeTagSafe (safe.ts, line 68-71) uses String.includes(), which is case-sensitive:

if (key === 'href') {
  if (val.includes('javascript:') || val.includes('data:')) {
    return
  }
  next[key] = val
}

Browsers treat URI schemes case-insensitively. DATA:text/css,... is the same as data:text/css,... to the browser, but 'DATA:...'.includes('data:') returns false.

PoC

useHeadSafe({
  link: [{
    rel: 'stylesheet',
    href: 'DATA:text/css,body{display:none}'
  }]
})

SSR output:

<link rel="stylesheet" href="DATA:text/css,body{display:none}">

The browser loads this as a CSS stylesheet. An attacker can inject arbitrary CSS for UI redressing or data exfiltration via CSS attribute selectors with background-image callbacks.

Any case variation works: DATA:, Data:, dAtA:, JAVASCRIPT:, etc.

Suggested fix

if (key === 'href') {
  const lower = val.toLowerCase()
  if (lower.includes('javascript:') || lower.includes('data:')) {
    return
  }
  next[key] = val
}

CWEs

References