Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-73492

CVE-2026-73492: Loofah Library XSS Vulnerability

CVE-2026-73492 is a cross-site scripting flaw in Loofah library affecting versions 2.25.0 to 2.25.2. The vulnerability allows javascript: and vbscript: URIs to bypass sanitization. This article covers technical details, affected versions, impact, and mitigation steps.

Published:

CVE-2026-73492 Overview

CVE-2026-73492 affects Loofah, a Ruby library for manipulating and transforming HTML and XML documents built on top of Nokogiri. Versions from 2.25.0 until 2.25.2 contain a flaw in Loofah::HTML5::Scrub.allowed_uri? that fails to reject javascript: or vbscript: URIs when the scheme is split by semicolon-less numeric character references such as :, , , or . Callers passing HTML-encoded strings directly to allowed_uri? may treat malicious URIs as safe. The vulnerability is classified as improper input neutralization leading to cross-site scripting [CWE-79].

Critical Impact

Applications that call allowed_uri? directly on HTML-encoded input can be tricked into approving javascript: URIs, enabling XSS in the rendered browser context.

Affected Products

  • Loofah 2.25.0
  • Loofah 2.25.1
  • Ruby applications using Loofah::HTML5::Scrub.allowed_uri? directly on HTML-encoded input

Discovery Timeline

  • 2026-08-12 - CVE-2026-73492 published to NVD
  • 2026-08-12 - Last updated in NVD database

Technical Details for CVE-2026-73492

Vulnerability Analysis

Loofah sanitizes untrusted HTML by validating URI schemes against an allow list. The allowed_uri? helper first calls CGI.unescapeHTML to decode HTML entities before applying the URI_PROTOCOL_REGEX check. CGI.unescapeHTML only decodes numeric character references that terminate with a semicolon. Modern browsers, however, will decode references without the trailing semicolon such as : for a colon or for a tab. The mismatch lets an attacker construct a payload like javascript:alert(1) that Loofah sees as a scheme-less string while a browser resolves it to javascript:alert(1).

This condition only impacts callers who pass HTML-encoded strings directly to allowed_uri?. Loofah's default sanitize() path is not affected because it operates on already-parsed DOM attribute values.

Root Cause

The root cause is inconsistent decoding semantics between CGI.unescapeHTML and browser HTML parsing. The scheme validator relied on the Ruby standard library to normalize entities before regex matching, but browsers accept malformed numeric character references that the standard library preserves verbatim. The result is a classic parser differential enabling filter bypass.

Attack Vector

An attacker supplies HTML-encoded input containing a dangerous scheme obfuscated with semicolon-less numeric character references. When downstream code applies allowed_uri? and renders the value into an href, src, or similar attribute, the browser decodes the entity and executes the resulting URI scheme. Exploitation requires an application code path that hands raw HTML-encoded strings to allowed_uri? rather than to the default sanitize() pipeline.

ruby
       CSS_WHITESPACE = " "
       CSS_PROPERTY_STRING_WITHOUT_EMBEDDED_QUOTES = /\A(["'])?[^"']+\1\z/
       DATA_ATTRIBUTE_NAME = /\Adata-[\w-]+\z/
-      URI_PROTOCOL_REGEX = /\A[a-z][a-z0-9+\-.]*:/ # RFC 3986
+
+      # Decimal (`:`) or hexadecimal (`:`) form, with or without the trailing semicolon that
+      # CGI.unescapeHTML requires but browsers do not.
+      NUMERIC_CHARACTER_REFERENCE = /&#(x[0-9a-f]+|[0-9]+);?/i
+
+      # A scheme (RFC 3986) followed by a protocol separator. The separator must recognize the same
+      # encoded-colon forms as PROTOCOL_SEPARATOR, otherwise a scheme split by an encoded colon (for
+      # example "javascript:alert(1)") would not be recognized as having a scheme and would skip
+      # protocol validation.
+      URI_PROTOCOL_REGEX = /\A[a-z][a-z0-9+\-.]*#{SafeList::PROTOCOL_SEPARATOR}/
 
       # Matches a valid MIME type "essence" (type "/" subtype, no parameters), used to
       # decide whether a data: URI mediatype is well-formed; a non-match is not a valid

Source: GitHub Commit f1be9d8. The patch replaces the naive URI_PROTOCOL_REGEX with one that recognizes the same encoded-colon forms browsers accept, ensuring schemes obfuscated with numeric character references are properly detected.

Detection Methods for CVE-2026-73492

Indicators of Compromise

  • HTTP request bodies or query strings containing javascript:, vbscript:, or similar patterns with numeric character references without trailing semicolons.
  • Log entries showing user-generated HTML attributes with entities like , , , or : inside href or src values.
  • Stored content in databases containing sanitized-but-encoded URIs that still resolve to dangerous schemes when rendered.

Detection Strategies

  • Audit application source for direct calls to Loofah::HTML5::Scrub.allowed_uri? outside the default sanitize() pipeline.
  • Perform dependency scanning to identify Ruby projects using Loofah versions 2.25.0 or 2.25.1.
  • Add regression tests that feed payloads such as javascript:alert(1) through the application's sanitization layer and assert removal.

Monitoring Recommendations

  • Enable web application firewall rules that flag numeric character references adjacent to scheme keywords (javascript, vbscript, data) in inbound requests.
  • Monitor content management and comment systems for stored HTML attributes containing decimal or hexadecimal entities within URI attributes.
  • Track browser-side Content Security Policy (CSP) violation reports for inline script execution originating from user-generated content.

How to Mitigate CVE-2026-73492

Immediate Actions Required

  • Upgrade Loofah to version 2.25.2 or later in all affected Ruby applications.
  • Inventory the codebase for direct invocations of allowed_uri? and route URI validation through the maintained sanitize() API where possible.
  • Deploy a strict Content Security Policy to reduce the blast radius of any remaining XSS bypasses.

Patch Information

The fix is included in Loofah 2.25.2, released via GitHub Release v2.25.2. Technical details are documented in GitHub Security Advisory GHSA-5qhf-9phg-95m2 and GitHub Pull Request #308.

Workarounds

  • Decode HTML entities on input before passing values to allowed_uri?, ensuring semicolon-less numeric character references are normalized first.
  • Reject user-supplied URI attributes containing &# sequences prior to sanitization.
  • Prefer the default Loofah.sanitize() and Loofah.scrub_fragment() APIs, which are not affected by this issue.
bash
# Upgrade Loofah in a Bundler-managed project
bundle update loofah --conservative

# Verify the installed version is 2.25.2 or later
bundle info loofah | grep -i version

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.