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
- CWE-79 · Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')