CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-8WHX-365G-H9VV

GHSA-8whx-365g-h9vv: HTML5 Named Whitespace Bypass in Loofah allowed_uri? Validation

Alon Barad
Alon Barad
Software Engineer

Jul 21, 2026·7 min read·4 visits

Executive Summary (TL;DR)

A bypass in Loofah's string validation helper allows attackers to construct executable javascript: URIs obfuscated with HTML5 named entities, leading to stored XSS.

The Loofah Ruby gem version 2.25.0 and 2.25.1 contains an incomplete validation vulnerability in its public string-level utility Loofah::HTML5::Scrub.allowed_uri?. This helper fails to detect 'javascript:' URIs that are split by HTML5 named whitespace character references such as 	 and 
. Applications manually invoking this utility to validate links are vulnerable to stored Cross-Site Scripting (XSS), as browsers parse and remove these entities during rendering.

Vulnerability Overview

The Loofah library is an HTML/XML manipulation and sanitization tool widely utilized in the Ruby on Rails ecosystem, specifically within libraries like Action Text to secure user-controlled rich text content. To assist developers with lightweight URI validation, Loofah exposes the public utility method Loofah::HTML5::Scrub.allowed_uri?. This method is designed to evaluate raw strings and verify that their schemes conform to a safe whitelist, such as http, https, or mailto, before they are written to a database or rendered inside browser-interpreted attributes like href or src.

In versions 2.25.0 and 2.25.1, this string-level validator is vulnerable to an incomplete validation bypass (CWE-184). When a user supplies URIs obfuscated with HTML5 named whitespace character references, the validation logic fails to decode these specific entities. Consequently, the utility is unable to isolate the underlying URI scheme and misidentifies the malicious string as a safe relative URI path, allowing it to pass without further sanitization.

This vulnerability highlights a critical distinction between Loofah's primary document/fragment parsing pipelines and its string-level utility methods. The default document sanitizer leverages Nokogiri to pre-process and normalize HTML entities before evaluating schemes, rendering the default parser resilient to this specific bypass. The vulnerability exclusively exposes environments that bypass full document parsing and directly invoke the allowed_uri? helper to validate standalone inputs.

Root Cause Analysis

The vulnerability originates from a misalignment between Ruby's entity-decoding mechanisms and modern HTML5 parsing specifications used by web browsers. Following a previous fix for numeric entity bypasses (GHSA-46fp-8f5p-pf2m), version 2.25.1 introduced a sanitization pipeline inside allowed_uri?. This pipeline was designed to strip raw control characters, decode HTML entities using Ruby's CGI.unescapeHTML, strip newly-uncovered control characters a second time, and normalize the schema to lowercase.

While Ruby's standard library helper CGI.unescapeHTML effectively decodes classic HTML4 named entities and decimal/hexadecimal numeric character references, it does not support HTML5-specific named character references. Under the WHATWG HTML5 specification, web browsers decode named references such as 	 to an ASCII Horizontal Tab character (U+0009) and 
 to an ASCII Line Feed character (U+000A). Because CGI.unescapeHTML ignores these strings, the obfuscated input passes through the decoding stage completely intact.

During the subsequent regex check, the string is evaluated against the URI_PROTOCOL_REGEX constant. Because the literal sequence of characters 	 or 
 resides within the protocol prefix (e.g., java	script), the validator fails to identify a valid URI scheme according to RFC 3986 guidelines. Since the string lacks a recognized scheme, Loofah treats the input as a safe relative path (such as a local directory path) and returns true, authorizing the application to save and render the malicious payload verbatim.

Once the output is delivered to the victim's browser, the rendering engine processes the HTML attributes and decodes the 	 entity into a literal horizontal tab. When the link is activated, the browser's WHATWG-compliant URL parser processes the URI. Following browser normalization specifications, the parser automatically strips tab, line feed, and carriage return characters from the string, reconstructing the executable javascript:alert(1) scheme and triggering immediate scripting execution.

Code Analysis

To understand the vulnerability, analyze the vulnerable sequence in Loofah 2.25.1:

# Vulnerable implementation in Loofah 2.25.1
def allowed_uri?(uri_string)
  # Replace control characters both before and after unescaping.
  uri_string = CGI.unescapeHTML(uri_string.gsub(CONTROL_CHARACTERS, ""))
    .gsub(CONTROL_CHARACTERS, "")
    .gsub(":", ":")
    .downcase

If the attacker supplies java	script:alert(1), the first gsub has no effect because there are no literal control characters. CGI.unescapeHTML encounters 	 but leaves it untouched because it is not a standard HTML4 entity. The second gsub also ignores it. The resulting string java&tab;script:alert(1) fails the regex validation for schemes and is accepted as relative.

The patched version in 2.25.2 rectifies this by defining a strict regex for HTML5 named whitespace references:

# Patched implementation in Loofah 2.25.2
WHITESPACE_CHARACTER_REFERENCES = /&(Tab|NewLine);/
 
# ...
 
def allowed_uri?(uri_string)
  # Control characters are stripped both before and after unescaping, since
  # unescaping can produce them. That strip must precede
  # WHITESPACE_CHARACTER_REFERENCES: removing a control character can reveal a
  # named whitespace reference.
  uri_string = CGI.unescapeHTML(uri_string.gsub(CONTROL_CHARACTERS, ""))
  uri_string.gsub!(CONTROL_CHARACTERS, "")
  uri_string.gsub!(WHITESPACE_CHARACTER_REFERENCES, "")
  uri_string.gsub!(":", ":")
  uri_string.downcase!

The sequence of operations in the patch is highly critical. The filter strips control characters first, which addresses malicious nested constructions (such as java&Ta�b;script:alert(1)). After the raw null byte is removed, the remaining string resolves to java	script:alert(1), which is then captured and eliminated by the WHITESPACE_CHARACTER_REFERENCES regex. This ensures that the validator evaluates the raw, reconstructed scheme correctly.

Exploitation Methodology

Exploitation of this vulnerability requires that the target application invoke Loofah::HTML5::Scrub.allowed_uri? as a standalone string validator for user input, saving the output exactly as supplied. When a victim loads the page and interacts with the rendered element, the browser decodes and runs the payload.

Below is a technical flowchart illustrating the lifecycle of an exploitation attempt:

Verified Proof-of-Concept Payloads:

  • Horizontal Tab Entity Injection: java	script:alert(document.domain)
  • Line Feed Entity Injection: java
script:alert(document.cookie)
  • Mixed Entity and Scheme Obfuscation: java	script:alert(1)
  • Nested Null Byte to Evade Naive Filters: java&Ta�b;script:alert(document.domain)

Impact Assessment

The impact of successful exploitation is Stored Cross-Site Scripting (XSS). Once a malicious link is written to the database, any user visiting the affected page and clicking the link will execute the payload in the context of their active session. Attackers can leverage this to hijack session credentials, exfiltrate sensitive cookies, perform unauthorized actions on behalf of the user, or inject malicious DOM elements.

While the underlying vulnerability receives a CVSS score of 2.3 from GitHub due to the specific scope of the standalone helper, the real-world impact inside applications that use this helper to validate profile links, markdown paths, or custom href attributes is comparable to a high-severity stored XSS. Security teams must treat any exposure of allowed_uri? as a critical vector for session compromise.

Currently, this vulnerability is not cataloged in CISA's Known Exploited Vulnerabilities (KEV) database, and there are no reports indicating active exploitation in ransomware or automated threat campaigns. The exploit maturity is classified as a Proof of Concept (PoC) because the mechanics are fully understood and verified via internal testing scripts, making exploitation simple if vulnerable versions of the library are in service.

Remediation and Mitigation

The most effective and recommended mitigation is to upgrade the loofah dependency to version 2.25.2 or above. This release updates the sanitization sequence and integrates the explicit removal of the 	 and 
 entity vectors prior to downcasing and regex evaluation.

To update your application via Bundler, modify your Gemfile to specify the safe version and run the update command:

bundle update loofah

If an immediate library upgrade is not possible due to dependency constraints, developers must implement an application-level wrapper to sanitize incoming strings prior to validation. Below is an example implementation of a safe validation wrapper:

module SafeUriValidator
  WHITESPACE_CHARACTER_REFERENCES = /&(Tab|NewLine);/i
 
  def self.allowed_uri?(uri_string)
    return false if uri_string.nil?
    
    # Pre-clean known HTML5 entities before passing to Loofah
    cleaned_uri = uri_string.gsub(WHITESPACE_CHARACTER_REFERENCES, "")
    
    Loofah::HTML5::Scrub.allowed_uri?(cleaned_uri)
  end
end

Architecturally, this vulnerability demonstrates the danger of relying on partial HTML decoding routines. When building verification layers, security teams should ensure that validating engines decode inputs using the exact same standard (such as the WHATWG HTML5 parser specification) as the client-side browsers destined to render the final output.

Official Patches

flavorjones/loofahFix commit implementing WHITESPACE_CHARACTER_REFERENCES filter.

Fix Analysis (1)

Technical Appendix

CVSS Score
2.3/ 10
CVSS:4.0/AV:N/AC:H/AT:N/PR:L/UI:N/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N

Affected Systems

loofah Ruby GemRuby on Rails applications using Action Text with custom link validation rules

Affected Versions Detail

Product
Affected Versions
Fixed Version
loofah
flavorjones
>= 2.25.0, < 2.25.22.25.2
AttributeDetail
CWE IDCWE-184 (Incomplete List of Disallowed Inputs)
Attack VectorNetwork (Unauthenticated)
CVSS Score2.3 (Low / Scope-Dependent)
ImpactStored Cross-Site Scripting (XSS)
Exploit StatusProof-of-Concept
Vulnerable MethodLoofah::HTML5::Scrub.allowed_uri?

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
CWE-184
Incomplete List of Disallowed Inputs

The product lacks an exhaustive list of prohibited inputs, allowing restricted values to bypass validation routines.

Known Exploits & Detection

GitHub Security AdvisoryExploit methodology and regression tests verifying bypass functionality using HTML5 whitespace entities.

Vulnerability Timeline

GitHub Advisory GHSA-46fp-8f5p-pf2m published; version 2.25.1 released.
2026-03-18
Bypass vulnerability responsibly reported by GitHub user @connorshea.
2026-07-21
Fix commit 5e91af861e3cdab47b91dd0b81f3afdfd13a5e19 merged and released in version 2.25.2.
2026-07-21
Advisory GHSA-8whx-365g-h9vv officially published.
2026-07-21

References & Sources

  • [1]GitHub Security Advisory GHSA-8WHX-365G-H9VV
  • [2]Loofah Repository Advisory Page
  • [3]Fix Commit
  • [4]Loofah v2.25.2 Release Tag
  • [5]Previous Related Advisory GHSA-46fp-8f5p-pf2m

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•42 minutes ago•CVE-2026-59879
8.7

CVE-2026-59879: Infinite Loop and Integer Overflow in Immutable.js List Sizing

CVE-2026-59879 describes a critical integer overflow vulnerability in the Immutable.js library when handling indices near 32-bit boundaries. An attacker can leverage this flaw to cause a denial of service via CPU thread lockup or process crashes, as well as data corruption through silent size truncation.

Amit Schendel
Amit Schendel
2 views•8 min read
•about 2 hours ago•CVE-2026-54291
8.2

CVE-2026-54291: Silent Channel-Binding Authentication Downgrade in PostgreSQL JDBC Driver (pgjdbc)

A critical security bypass and algorithm downgrade vulnerability in the PostgreSQL JDBC Driver (pgjdbc) allows Man-in-the-Middle (MITM) attackers to silently bypass channel binding requirements. When configured with `channelBinding=require`, the driver fails to assert that the negotiated SCRAM mechanism utilizes channel binding, allowing downgrade to plain SCRAM-SHA-256 when encountering unsupported server certificate signature algorithms (such as Ed25519 or Ed448).

Alon Barad
Alon Barad
4 views•7 min read
•about 3 hours ago•CVE-2026-56170
7.5

CVE-2026-56170: Remote Denial of Service via Resource Exhaustion in ASP.NET Core

CVE-2026-56170 is a high-severity Remote Denial of Service (DoS) vulnerability in Microsoft's ASP.NET Core framework. The vulnerability spans three separate resource-management vectors within the ASP.NET Core ecosystem, including SignalR Stateful Reconnect allocations, JSON Patch Type Confusion leading to stack exhaustion, and Kestrel HTTP/2 synchronization issues. An unauthenticated remote attacker can exploit these issues to cause process-terminating exceptions, rendering applications unavailable.

Amit Schendel
Amit Schendel
4 views•7 min read
•about 5 hours ago•CVE-2026-50525
7.5

CVE-2026-50525: Denial of Service Vulnerability in Microsoft .NET XML Cryptography Stack

CVE-2026-50525 is a high-severity Denial of Service (DoS) vulnerability in the Microsoft .NET XML Cryptography stack. The vulnerability resides in the `System.Security.Cryptography.Xml` library, specifically within the `EncryptedXml` processing engine. Unauthenticated remote attackers can exploit this flaw by sending specifically crafted XML documents containing nested or recursive structures, or utilizing resource-intensive transforms. Processing such payloads leads to infinite CPU loops, stack exhaustion, or memory starvation, resulting in application termination.

Amit Schendel
Amit Schendel
5 views•6 min read
•about 6 hours ago•CVE-2026-50659
6.5

CVE-2026-50659: SMTP Command and Header Injection in .NET System.Net.Mail

An improper encoding and escaping vulnerability in the .NET SMTP client component allows network-based attackers to perform SMTP command smuggling and email spoofing by injecting control characters into email fields.

Alon Barad
Alon Barad
5 views•8 min read
•about 7 hours ago•CVE-2026-50651
7.5

CVE-2026-50651: Denial of Service via Uncontrolled Resource Allocation in .NET System.Net.Http

CVE-2026-50651 is a high-severity Denial of Service vulnerability in Microsoft .NET runtimes, SDKs, and Visual Studio installations. It stems from a weakness in System.Net.Http (CWE-770), where the HTTP/2 connection handling state machine fails to throttle server-initiated protocol streams and control frames. An attacker-controlled server can exploit this by returning highly fragmented or infinite control and continuation frame sequences. This forces the client to allocate memory indefinitely on the managed heap, eventually provoking an unhandled Out-of-Memory (OOM) exception and application crash.

Amit Schendel
Amit Schendel
6 views•6 min read