Listen to this Post
How CVE-2026-53606 Works
The vulnerability resides in how sanitize-html gates its URI scheme validation. The library uses the `allowedSchemesAppliedToAttributes` configuration option (default: ['href', 'src', 'cite']) to determine which attributes should be checked by the `naughtyHref()` function. This function is responsible for blocking dangerous URI schemes like `javascript:` and vbscript:.
The problem is that the HTML specification defines over 10 attributes that accept URIs (action, formaction, data, poster, background, ping, xlink:href, dynsrc, lowsrc), but none of these are included in the default gate list. When a developer allows any of these attributes in their configuration (a non-default configuration), `javascript:` URIs pass through completely unmodified, enabling XSS.
The library has zero awareness of these URI-bearing attributes — none appear anywhere in the 854-line source file. No warning mechanism exists, and the README provides no security guidance about expanding `allowedSchemesAppliedToAttributes` when allowing form or media attributes.
The root cause is in `index.js:329` where the gate that controls scheme validation is defined:
if (options.allowedSchemesAppliedToAttributes.indexOf(a) >= 0) {
if (naughtyHref(name, value)) {
delete frame.attribs[bash];
return;
}
}
The default list at line 829 is: allowedSchemesAppliedToAttributes: ['href', 'src', 'cite'].
The `naughtyHref()` function (lines 627-667) correctly blocks dangerous schemes, but it has exactly 2 call sites in the entire codebase (lines 330 and 395), both inside the `indexOf` gate. There is no ungated path.
When an attribute name is action, formaction, data, poster, background, etc.:
– `indexOf(‘action’)` returns `-1`
– The `if` block is skipped entirely
– `naughtyHref()` is never called
– `javascript:alert(1)` passes through unmodified
The `escapeHtml()` function at line 464 provides no defense — it only encodes `& < > “` characters, which are not present in javascript:alert(1).
Data Flow for a malicious payload:
1. `htmlparser2` parses → `tag=’form’`, `attribs={action:’javascript:alert(document.cookie)’}`
2. `index.js:298` → `allowedAttributes` check: `’action’` in developer config → PASS
3. `index.js:329` → `[‘href’,’src’,’cite’].indexOf(‘action’)` → `-1` → SKIP `naughtyHref()`
