Jul 22, 2026·5 min read·3 visits
Loofah fails to sanitize the SVG 2 plain 'href' attribute, enabling attackers to bypass local-reference restrictions and inject external resources or trigger Cross-Site Scripting.
A security logic flaw in Loofah, a Ruby HTML/XML sanitization library, allowed unauthenticated attackers to bypass local-reference restrictions on SVG elements. Prior to version 2.25.2, Loofah only sanitized the legacy namespaced "xlink:href" attribute when enforcing local URI fragments on SVG elements like "<use>". It did not validate or sanitize the plain, non-namespaced "href" attribute introduced in the SVG 2 standard. This structural omission allowed attackers to construct SVG elements referencing external domains, paving the way for arbitrary resource loading and cross-site scripting (XSS).
The Ruby XML/HTML sanitization library, Loofah, leverages the Nokogiri parsing engine to scrub untrusted user inputs. To defend against resource hijacking, data tracking, and Cross-Site Scripting (XSS), the library implements strict policies on SVG structure manipulation. Specifically, certain SVG elements such as <use>, <feImage>, and <animate> are restricted to internal page references (local URI fragments beginning with #) to prevent the browser from loading external, unvalidated materials.
In the SVG 1.1 specification, linking and resource mapping were primarily handled using the namespaced xlink:href attribute. However, the SVG 2 specification simplified this mechanism by introducing the plain, unnamespaced href attribute. Modern web browsers natively render both forms, treating them as interchangeable.
Because Loofah was only configured to inspect and sanitize the namespaced xlink:href attribute, inputs utilizing the modern SVG 2 href attribute bypassed the sanity checks entirely. This allowed external resource URIs to pass unaltered through the sanitizer, leaving downstream web clients vulnerable to unauthorized connections and arbitrary script execution.
The core vulnerability stems from an incomplete logic constraint within Loofah's attribute scrubbing implementation located in lib/loofah/html5/scrub.rb. When processing incoming SVG components, the scrubber iterates over element nodes and compares them against SafeList::SVG_ALLOW_LOCAL_HREF, a predefined set of elements permitted to reference internal fragments.
To ensure security, any element utilizing a link attribute was checked against a regular expression /^\s*[^#\s].*/m. This regular expression matches any string that does not begin with the # symbol, signaling an external or remote resource. If a match occurred, the attribute node was slated for immediate removal via attr_node.remove.
However, the code conditionally executed this validation check only when the literal string attr_name == "xlink:href" was matched. This tight coupling to the namespaced string meant that when Nokogiri encountered the SVG 2 standard plain href attribute, the condition failed. The scrubber bypassed the validation logic, resulting in the preservation of the untrusted remote URL in the finalized document output.
An analysis of the vulnerable source code in lib/loofah/html5/scrub.rb highlights the implementation flaw:
# Vulnerable Implementation
next unless SafeList::SVG_ALLOW_LOCAL_HREF.include?(node.name) &&
attr_name == "xlink:href" &&
attr_node.value =~ /^\s*[^#\s].*/m
attr_node.removeIf the incoming payload contains <use href="http://attacker.com/evil.svg#payload">, the parser extracts attr_name as "href". Because the string equality test attr_name == "xlink:href" evaluates to false, the entire condition resolves to false. The execution flows to the next attribute, bypassing the attr_node.remove instruction completely.
To resolve this, the maintainers defined a unified set containing both namespaces in lib/loofah/html5/safelist.rb:
# Patched SafeList Additions
SVG_HREF_ATTRIBUTES = Set.new([
"xlink:href",
"href",
])This collection is integrated into the updated scrubber logic in lib/loofah/html5/scrub.rb:
# Patched Implementation
next unless SafeList::SVG_ALLOW_LOCAL_HREF.include?(node.name) &&
SafeList::SVG_HREF_ATTRIBUTES.include?(attr_name) &&
attr_node.value =~ /^\s*[^#\s].*/m
attr_node.removeUnder this patched flow, any attribute whose name is registered in SVG_HREF_ATTRIBUTES is systematically evaluated against the remote resource regex, closing the bypass vector.
Exploiting this vulnerability requires sending a constructed SVG fragment containing a targeted element such as <use> or <feImage> that utilizes the plain href attribute. Because Loofah leaves this attribute unmodified, the resulting payload is sent directly to the client browser.
In a typical scenario, an attacker injects a <use> element pointing to an external domain hosting a malicious SVG file with embedded JavaScript. Under standard browser security restrictions, cross-origin resource access may block external XML documents unless specifically permitted by CORS or if the application shares the same origin.
An alternative attack vector targets the <feImage> element. By embedding <feImage href="https://attacker.com/beacon.png" />, an attacker can bypass traditional tracking protection. When the client loads the document, the browser requests the tracking resource, leaking the user's IP address, browser metadata, and session-related telemetry.
The primary impact of this vulnerability is the breakdown of the application's sanitization guarantees, leading to Cross-Site Scripting (XSS) and unauthorized external resource load operations. If the application handles user-uploaded documents or allows arbitrary markdown/HTML inputs, this bypass can lead to sensitive cookie extraction, local session hijacking, and defacement of the hosting platform.
The vulnerability is classified as CVSS 4.7 (Medium) because exploitation is subject to structural browser controls. Cross-origin restrictions restrict the execution of external SVG scripts in several modern browser runtimes, requiring specific environment configurations or same-origin deployment schemes to achieve fully interactive remote code execution.
Because this vulnerability was assigned a GitHub Security Advisory (GHSA-9WJQ-CP2P-HRGF) rather than a CVE identifier, standard EPSS (Exploit Prediction Scoring System) metrics do not track this vector. No active, automated exploitation campaigns have been observed in the wild, classifying the current threat index as analytical and proof-of-concept.
The definitive remediation for this vulnerability is upgrading the Loofah dependency to version 2.25.2 or later. This release correctly normalizes all input variations, ensuring that modern and legacy SVG standard linkages undergo the same validation sequence.
While this patch is highly effective, security engineers should monitor for parser discrepancies between Nokogiri (based on libxml2) and the client browser's rendering engine. If Nokogiri resolves nested XML namespaces differently than a target browser, specialized namespace manipulation (e.g., <svg xmlns:custom="http://www.w3.org/1999/xlink"><use custom:href="..." />) could theoretically lead to secondary bypasses.
To establish depth of defense, applications should deploy a strict Content Security Policy (CSP). Setting object-src 'none' and specifying restricted source directives for img-src limits the browser's ability to fetch and execute external SVG links, regardless of the sanitization state of the markup.
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
loofah rubygems | < 2.25.2 | 2.25.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 Score | 4.7 (Medium) |
| EPSS Score | Not Applicable |
| Impact | Cross-Site Scripting (XSS) / Resource Injection |
| Exploit Status | Proof-of-Concept |
| KEV Status | Not Listed |
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
A critical second-order code injection vulnerability exists in the migration generation engine of TypeORM. When TypeORM introspects a database schema to automatically generate migration files, it writes schema metadata directly into JavaScript/TypeScript migration files inside ES2015 template literals. Because the generator failed to sanitize template literal string interpolation markers and backslashes, attackers with control over database metadata can execute arbitrary code on the developer environment or within a CI/CD pipeline.
A critical HTML sanitization bypass vulnerability in the Ruby library Loofah allows unauthenticated remote attackers to execute Stored Cross-Site Scripting (XSS) attacks. By using semicolon-less numeric character references (NCRs) to encode protocol characters, attackers can evade backend URI verification filters while ensuring the malicious protocol is successfully decoded and executed by client-side web browsers.
GHSA-HRXH-6V49-42GF is a critical security advisory addressing two distinct vulnerabilities within gRPC-Go: an HTTP/2 Control Buffer Flooding weakness that allows unauthenticated denial of service, and xDS Role-Based Access Control parser weaknesses that lead to authorization bypasses and application panics.
An unauthenticated memory-leak Denial of Service (DoS) vulnerability exists in the Node.js Adapter for Hono (@hono/node-server) during the WebSocket handshake upgrade process. If a client initiates a WebSocket upgrade but the process is aborted or fails, resources are permanently retained in memory, leading to heap exhaustion.
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.
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.