Skip to main content

Symfony HtmlSanitizer CVE-2026-48761

| EUVDEUVD-2026-44389 MEDIUM
Cross-site Scripting (XSS) (CWE-79)
2026-06-15 https://github.com/symfony/symfony GHSA-x5qj-865h-mgvm
5.3
CVSS 4.0 · Vendor: https://github.com/symfony/symfony
Share

Severity by source

Vendor (https://github.com/symfony/symfony) PRIMARY
5.3 MEDIUM
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
vuln.today AI
6.1 MEDIUM

Network-accessible stored XSS with scope change; PR:N since the sanitizer layer imposes no auth requirement; UI:R as victim page load is needed to trigger execution.

3.1 AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
4.0 AV:N/AC:L/AT:P/PR:N/UI:P/VC:N/VI:L/VA:N/SC:L/SI:L/SA:N

Primary rating from Vendor (https://github.com/symfony/symfony).

CVSS VectorVendor: https://github.com/symfony/symfony

CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
P
Scope
X

Lifecycle Timeline

3
CVSS changed
Jul 14, 2026 - 20:22 NVD
5.3 (MEDIUM)
Source Code Evidence Fetched
Jun 15, 2026 - 17:19 vuln.today
Analysis Generated
Jun 15, 2026 - 17:19 vuln.today

DescriptionCVE.org

Description

Symfony\Component\HtmlSanitizer\Visitor\AttributeSanitizer\UrlAttributeSanitizer::getSupportedAttributes() enumerates the attribute names whose values are scrubbed through UrlSanitizer::sanitize() (scheme and host allow-lists, javascript: rejection, BiDi check, etc.). The list is ['src', 'href', 'lowsrc', 'background', 'ping', 'action', 'formaction', 'poster', 'cite']. Other URL-bearing attributes are absent: <object data=…>, <applet codebase=…>, <applet archive=…> and <object archive=…>, <iframe longdesc=…> and <img longdesc=…>. When an integrator opts these elements/attributes in via allowElement('object', ['data']), allowElement('applet', ['codebase']), etc., or via allowAttribute(), no URL sanitization runs: data="javascript:alert(1)" and similar payloads ship through unchanged into the output, enabling stored XSS.

<meta http-equiv="refresh" content="0; url=…"> is the same class of bug routed differently: the URL is embedded inside a multi-field content attribute that the per-attribute sanitizer cannot detect from the attribute name alone. Integrators who enable <meta> with the content attribute (e.g. via allowStaticElements()) see content="0; url=javascript:alert(1)" pass through, producing a refresh-driven navigation to a javascript: URL.

Default configurations are not affected: <object>, <applet> and <iframe> are not in W3CReference::BODY_ELEMENTS and <meta> requires an explicit opt-in to <head> context. The vulnerability surface is integrators who explicitly allow any of those elements together with the listed URL-bearing attributes.

Resolution

UrlAttributeSanitizer now also routes data, codebase, archive and longdesc through UrlSanitizer::sanitize(). A new MetaRefreshAttributeSanitizer registered as a default attribute sanitizer detects the <delay>; url=<url> syntax inside <meta content>, sanitizes the embedded URL, and drops the attribute if the URL is rejected; non-refresh meta content values are passed through unchanged.

The patches for this issue are available here for branch 6.4 (and forward-ported to 7.4, 8.0 and 8.1).

Credits

Symfony would like to thank Scott Arciszewski (Trail of Bits) for reporting the issue and Nicolas Grekas for providing the fix.

AnalysisAI

Stored XSS in the Symfony HtmlSanitizer component (symfony/html-sanitizer) allows injection of javascript: scheme URLs through HTML attributes not covered by the library's URL sanitization allow-list. The UrlAttributeSanitizer hardcodes a fixed set of URL-bearing attributes to sanitize, omitting data (on object), codebase and archive (on applet), and longdesc (on iframe/img); a related gap allows javascript: URLs embedded in meta http-equiv=refresh content values to pass through unchanged. Only non-default configurations that explicitly opt in to those element-attribute combinations via allowElement() or allowAttribute() are affected - default Symfony configurations are confirmed safe. No public exploit code has been identified at time of analysis, though the vendor advisory includes functional proof-of-concept payloads; the issue was reported by Scott Arciszewski of Trail of Bits.

Technical ContextAI

The Symfony HtmlSanitizer component (composer packages symfony/html-sanitizer and symfony/symfony, CWE-79) implements an allow-list-driven HTML sanitizer. Its UrlAttributeSanitizer class maintains a hardcoded list of attributes whose values are passed through UrlSanitizer::sanitize() for scheme validation (javascript: rejection), host allow-listing, and BiDi checks. That list - src, href, lowsrc, background, ping, action, formaction, poster, cite - omits several HTML attributes that also carry navigable or executable URLs: data on object elements, codebase and archive on applet and object elements, and longdesc on iframe and img elements. A second class of gap affects meta http-equiv=refresh: that element encodes its URL inside the composite content attribute (e.g., 0; url=javascript:alert(1)), making it undetectable by a per-attribute-name sanitizer. The root cause (CWE-79) is an incomplete output filter - the sanitizer correctly handles known URL sinks but its enumeration of those sinks is incomplete. The fix adds data, codebase, archive, and longdesc to UrlAttributeSanitizer and introduces a new MetaRefreshAttributeSanitizer that parses the delay;url= syntax and subjects the embedded URL to the same UrlSanitizer pipeline.

RemediationAI

Upgrade symfony/html-sanitizer (or symfony/symfony) to the patched releases: 6.4.41 for the 6.x series, 7.4.13 for the 7.x series, or 8.0.13 for the 8.0.x series, as documented in the security advisory at https://github.com/symfony/symfony/security/advisories/GHSA-x5qj-865h-mgvm; the patch commit is https://github.com/symfony/symfony/commit/069a70f9f26e61e9de3b7f9a864a86ed24b36bd0. If an immediate upgrade is not possible, audit every HtmlSanitizerConfig instance in the application and remove any explicit allowElement() or allowAttribute() calls that permit object with data, applet with codebase or archive, object with codebase, iframe or img with longdesc, or meta with content - removing these allowances eliminates the attack surface entirely but may break intentional rich-content features. Applications that rely on meta refresh functionality should delay that workaround until the patch can be applied, as removing the attribute may disrupt redirect-driven flows. No generic compensating controls (WAF rules, CSP) reliably substitute for the library-level fix because the payload reaches stored state before any response-phase control acts on it.

Share

CVE-2026-48761 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy