CVE-2026-31873

Updated on 12 Mar 2026

Severity

6.1 Medium severity

Details

CVSS score
6.1
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N

Overview

About vulnerability

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
}

Details

Affected product:
head , nuxt , unhead
Affected packages:
unhead @ 1.11.20 (+28 more)