Affected versions
Symfony HTML Sanitizer versions >=6.1, <6.4.50, >=7, <7.4.23, >=8, <8.1.11 are affected by this security issue.
The issue has been fixed in Symfony HTML Sanitizer 6.4.50, 7.4.23, 8.1.11.
Description
W3CReference::ATTRIBUTES marks srcset and imagesrcset as allowed attributes, but UrlAttributeSanitizer::getSupportedAttributes() does not list them, so no URL sanitizer is registered for either. The DOM visitor preserves an attribute value verbatim when no sanitizer handles it, so attacker-controlled responsive-image URL lists survive unchanged and the media scheme and host allow-lists are bypassed. The fixes for CVE-2026-45753 and CVE-2026-48761 extended the same attribute list but did not cover these two attributes.
The same policy correctly drops the equivalent img[src] value, so this is not a configuration mistake but a missing sanitizer for two browser-active URL attributes.
1 2 3 4 5 6 7 8 9
$config = (new HtmlSanitizerConfig())->allowSafeElements()
->allowMediaSchemes(['https'])->allowMediaHosts(['trusted.example']);
$sanitizer = new HtmlSanitizer($config);
$sanitizer->sanitize('<img srcset="https://evil.example/a.png 1x" alt="x">');
// srcset survives, browser fetches from evil.example
$sanitizer->sanitize('<img src="https://evil.example/a.png" alt="x">');
// src correctly dropped
source[srcset] and, in the head context, link[rel=preload][imagesrcset] behave the same way. The confirmed primitive is a browser-active URL policy bypass, not JavaScript execution.
Exploitation requires the application to sanitize attacker-controlled HTML with a configuration that allows these attributes, through allowSafeElements(), allowStaticElements() or an explicit opt-in, and to rely on allowMediaHosts(), allowMediaSchemes() or forceHttpsUrls() to restrict media URLs. The severity is rated low on that basis.
Resolution
srcset and imagesrcset are now sanitized. Because they carry a comma-separated list of candidates rather than a single URL, the value is parsed following the HTML srcset parsing rules, which correctly handles commas inside URLs and trailing width or density descriptors. Each candidate URL is passed through UrlSanitizer::sanitize() against the media policy, rejected candidates are dropped, and survivors are re-serialized with their descriptors intact. If every candidate is rejected, or the value is empty or holds only separators, the attribute is dropped, consistent with a rejected src, letting the browser fall back to the already sanitized src.
The patches for this issue are available here for branch 6.4 (and forward-ported to 7.4, 8.1 and 8.2). They require the patch for CVE-2026-118517, available here. Without it, a candidate written without //, like http:evil.example/a.png, is not checked against the media host allow-list.
Credits
We would like to thank Shriyansh Gupta, Ilia Alshanetsky and 李智遥 for independently reporting the issue.