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



CVE-2026-126078

CVE-2026-126078: Cross-Site Scripting in Ruby on Rails Action View highlight Helper

Amit Schendel
Amit Schendel
Senior Security Researcher

Nov 13, 2026·9 min read·2 visits

Executive Summary (TL;DR)

An improper input neutralization flaw (CWE-79) in Ruby on Rails Action View (< 8.0.5.2, < 8.1.4.1) allows Cross-Site Scripting (XSS) when using the highlight view helper with custom :highlighter strings containing placeholders inside HTML attributes.

CVE-2026-126078 is a Cross-Site Scripting (XSS) vulnerability classified under CWE-79 affecting the Action View component of Ruby on Rails in versions prior to 8.0.5.2 and 8.1.4.1. The vulnerability resides in the ActionView::Helpers::TextHelper#highlight method when invoked with a custom :highlighter template that places capture group placeholders inside HTML attribute values. Because matched substrings are substituted without HTML escaping after initial sanitization preserves literal quotation marks, an attacker controlling the input text or target search phrase can break out of the surrounding attribute delimiter and inject arbitrary HTML attributes or JavaScript event handlers.

Vulnerability Overview

Action View is the template rendering and view generation framework within Ruby on Rails. It provides built-in view helper modules designed to construct HTML elements and format text while managing output encoding through Rails' ActiveSupport::SafeBuffer (html_safe) mechanism. Among these helpers, ActionView::Helpers::TextHelper#highlight locates specified phrases within a given block of text and wraps each occurrence in an HTML snippet.

In Rails versions prior to 8.0.5.2 and 8.1.4.1, ActionView::Helpers::TextHelper#highlight is vulnerable to Cross-Site Scripting (CWE-79). The method accepts an optional :highlighter string parameter that uses regex backreference syntax (such as \1) to interpolate the matched substring into custom HTML markup. After performing string substitution across non-tag text segments, the helper marks the resulting string as html_safe, bypassing subsequent automatic template escaping.

When an application configures a :highlighter template that places the \1 placeholder inside a quoted HTML attribute—a pattern previously demonstrated in the official Rails API documentation ('<a href="search?q=\1">\1</a>')—the matched substring is inserted directly into the attribute without escaping quotation characters. Although highlight sanitizes input text by default prior to substitution, HTML sanitization intentionally leaves literal double quotes (") and single quotes (') unescaped within plain text nodes.

Consequently, if an attacker controls the highlighted text or the search phrase and includes quotation marks, the substituted match terminates the quoted HTML attribute prematurely. The attacker can then inject arbitrary HTML attributes, such as onfocus, onclick, or onload event handlers, into the generated tag. This results in either Reflected or Stored Cross-Site Scripting depending on how the application sources the text and phrase arguments.

Root Cause Analysis

The root cause of CVE-2026-126078 stems from a context mismatch between HTML node sanitization and regex string replacement inside ActionView::Helpers::TextHelper#highlight, combined with an edge case in the regular expression used to tokenize HTML tags and text segments.

By default, highlight sanitizes the input text parameter using the sanitize helper unless sanitize: false is explicitly passed. HTML sanitization parses the input fragment, removes disallowed elements or attributes, and serializes the DOM tree back into an HTML string. During this serialization phase, literal quote characters (" and ') located inside text nodes do not require entity encoding to remain safe in an HTML element body context; in fact, Rails' sanitizer converts character references like &quot; back into literal " characters.

Following sanitization, highlight splits the string into HTML tag starts and non-tag segments using text.scan(/<[^>]*|[^<]+/). For segments that do not start with <, the vulnerable implementation called Ruby's native String#gsub!(pattern, highlighter). When String#gsub! expands a backreference like \1, it copies the exact raw bytes of the captured text directly into the replacement string. If the :highlighter template places \1 inside an HTML attribute context (e.g., href="...\1..."), the unescaped " from the text node context transitions directly into a double-quoted attribute context without re-encoding, breaking the attribute boundary.

Additionally, the tokenization regex /<[^>]*|[^<]+/ exhibited a structural boundary defect. Because <[^>]* matches from < up to (but not including) the closing > of an HTML tag, the closing > character is captured as the very first character of the subsequent [^<]+ non-tag segment. If a user-supplied search phrase matched that leading > character, highlight replaced the tag's closing delimiter with the highlighter markup (or &gt;), corrupting the surrounding HTML structure and turning subsequent text into attributes of the preceding HTML tag.

Code Analysis

The vulnerability was remediated in commits 06938194b4fd59e1d2c8ab4a781f3c1e2b763425 (for the 8.1 / main branch) and c796f6198837479ada13290eb8fa767b5219a58a (for the 8.0 branch) within actionview/lib/action_view/helpers/text_helper.rb.

In the unpatched code, highlight iterated over the scanned segments and passed the highlighter string directly as the replacement argument to segment.gsub!:

# Vulnerable implementation in actionview/lib/action_view/helpers/text_helper.rb
patterns = Array(phrases).map { |phrase| Regexp === phrase ? phrase : Regexp.escape(phrase) }
pattern = /(#{patterns.join("|")})/i
highlighter = options.fetch(:highlighter, '<mark>\1</mark>') unless block
 
text.scan(/<[^>]*|[^<]+/).each do |segment|
  if !segment.start_with?("<")
    if block
      segment.gsub!(pattern, &block)
    else
      # FLAW 1: Direct unescaped substitution of backreferences (\1) into highlighter
      # FLAW 2: pattern can match the leading '>' closing the previous tag
      segment.gsub!(pattern, highlighter)
    end
  end
end.join

The patch modifies both the pattern matching boundaries and the replacement mechanism:

# Patched implementation in actionview/lib/action_view/helpers/text_helper.rb
patterns = Array(phrases).map { |phrase| Regexp === phrase ? phrase : Regexp.escape(phrase) }
pattern = /(#{patterns.join("|")})/i
 
# FIX 2: Negative lookahead prevents matching at the start of a segment that follows a tag,
# protecting the closing '>' character of the preceding HTML tag.
pattern_after_tag = /(?!\A)#{pattern}/
highlighter = options.fetch(:highlighter, '<mark>\1</mark>') unless block
 
text.scan(/<[^>]*|[^<]+/).each_with_index do |segment, index|
  if !segment.start_with?("<")
    segment_pattern = index > 0 ? pattern_after_tag : pattern
 
    if block
      segment.gsub!(segment_pattern, &block)
    else
      # FIX 1: Manually expand \0 through \9 and pass each capture group
      # through ERB::Util.html_escape_once to encode quotes and special characters.
      segment.gsub!(segment_pattern) do
        match = Regexp.last_match
        highlighter.gsub(/\\(\d)/) { ERB::Util.html_escape_once(match[$1.to_i]) }
      end
    end
  end
end.join

Fix Completeness Assessment

By switching from segment.gsub!(pattern, highlighter) to the block form of gsub!, the patched code intercepts Regexp.last_match and manually expands numbered placeholders \0 through \9. Each matched capture group is passed through ERB::Util.html_escape_once, which converts " to &quot; and ' to &#39; without double-escaping existing HTML entities. Furthermore, pattern_after_tag = /(?!\A)#{pattern}/ ensures that any non-tag segment following an HTML tag (index > 0) cannot match at position \A (index 0, where the closing > resides).

> [!NOTE] > While the patch prevents breaking out of quoted HTML attributes and element bodies, ERB::Util.html_escape_once is not sufficient if an application places \1 inside an unquoted attribute, a javascript: URI scheme, an inline <script> or <style> block, or an HTML-interpreting attribute like srcdoc. The patch explicitly updates the method documentation to warn developers against placing placeholders in those contexts and replaces the <a href="search?q=\1"> documentation example with <mark title="\1">\1</mark>.

Exploitation

Exploiting CVE-2026-126078 requires an application to invoke highlight with three specific conditions:

  1. The :highlighter option is set to a custom template containing a numbered backreference (\1, \0, etc.) inside a quoted HTML attribute (or a regex phrase match starts with > immediately after an HTML tag).
  2. Either the text being highlighted or the phrases array being matched contains attacker-controlled input that permits matching a substring containing quotation marks (" or ').
  3. The user views or interacts with the rendered HTML view.

Proof-of-Concept Analysis

Consider a search results template that uses the pattern previously shown in the official Rails documentation, where both the body content and search query reflect user input:

# Controller
@query = params[:q]
@article_snippet = "Showing results for: #{params[:q]}"
 
# View (ERB)
<%= highlight(@article_snippet, @query, highlighter: '<a href="/search?q=\1">\1</a>') %>

An attacker crafts a request with the following query parameter:

GET /search?q=rails%22%20onfocus=%22alert(document.domain)%22%20autofocus=%22 HTTP/1.1
Host: vulnerable-app.example.com

When highlight processes the input on an unpatched version of Rails:

  1. sanitize(@article_snippet) executes. Because the input contains no HTML tags (< or >), the literal double quotes inside rails" onfocus="alert(document.domain)" autofocus=" remain unmodified.
  2. Regexp.escape(@query) escapes the query for regex matching, matching the exact payload inside @article_snippet.
  3. segment.gsub!(pattern, '<a href="/search?q=\1">\1</a>') substitutes the payload into \1.
  4. The resulting HTML string is marked html_safe and rendered into the HTTP response:
Showing results for: <a href="/search?q=rails" onfocus="alert(document.domain)" autofocus="">rails" onfocus="alert(document.domain)" autofocus="</a>

When the victim's browser parses this markup, the href attribute closes right after rails. The browser interprets onfocus="alert(document.domain)" and autofocus="" as distinct attributes on the <a> element, automatically focusing the link on page load and executing the arbitrary JavaScript payload.

Tag Boundary Exploitation

In the secondary vector fixed by the patch, if text contains HTML tags (such as <span>text</span>) and the attacker controls phrases (passing >), the unpatched scanner split the string into ["<span", ">text", "</span", ">"]. Matching > on the second segment ">text" replaced the closing bracket of <span with <mark>></mark>text, producing malformed HTML <span<mark>></mark>text</span> and corrupting tag boundaries.

Impact Assessment

Successful exploitation of CVE-2026-126078 enables arbitrary JavaScript execution within the security context of the victim's browser session (Scope: Changed). The vulnerability carries a CVSS v3.1 Base Score of 6.1 (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N).

Once client-side script execution is achieved, an attacker can perform unauthorized actions on behalf of the authenticated user, bypass Cross-Site Request Forgery (CSRF) protections by reading the csrf-token meta tag from the DOM, exfiltrate sensitive information displayed on the page, or steal session identifiers if session cookies are not protected with the HttpOnly flag.

The scope of affected applications is constrained by configuration requirements. Applications that rely on the default :highlighter value ('<mark>\1</mark>') or pass a Ruby block to highlight (highlight(text, phrases) { |match| ... }) using standard Rails tag helpers are not vulnerable to the attribute injection vector. However, because the vulnerable '<a href="search?q=\1">\1</a>' pattern was explicitly included in the official Rails API documentation for TextHelper#highlight, applications where developers copied the documented example directly into production views are exposed.

According to FIRST EPSS metrics, CVE-2026-126078 currently holds an EPSS score of 0.00338 (0.34%, 27.57th percentile), and it is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog.

Remediation

To remediate CVE-2026-126078, upgrade Ruby on Rails (rails and actionview gems) to the patched maintenance releases:

  • Rails 8.1 Series: Upgrade to version 8.1.4.1 or later.
  • Rails 8.0 Series: Upgrade to version 8.0.5.2 or later.

Update your application's Gemfile to specify the patched release version and run Bundler:

bundle update rails actionview

Workarounds and Secure Coding Practices

If an immediate framework upgrade cannot be deployed, developers can mitigate the vulnerability at the application layer by refactoring calls to highlight:

  1. Use the Block Form with Tag Helpers: Replace string-based :highlighter options that construct links or attributes with the block syntax paired with link_to or content_tag (tag.*). Rails' tag helpers automatically enforce proper URL and attribute escaping:
# Vulnerable string-based highlighter:
highlight(text, query, highlighter: '<a href="search?q=\1">\1</a>')
 
# Secure block-based alternative:
highlight(text, query) do |match|
  link_to(match, search_path(q: match))
end
  1. Avoid Non-HTML Contexts in :highlighter: Even after applying the patch, never place \1 inside href URLs without URL-encoding (which the block form handles via search_path), unquoted attributes, <script> tags, or inline event handlers. Restrict string-based :highlighter templates strictly to element text bodies (e.g., <mark>\1</mark>) or double-quoted data/text attributes (e.g., <mark title="\1">\1</mark>).

Official Patches

Ruby on RailsGitHub Security Advisory GHSA-v6rj-xm57-3p59
Ruby on RailsRuby on Rails v8.0.5.2 Release Notes
Ruby on RailsRuby on Rails v8.1.4.1 Release Notes

Fix Analysis (2)

Technical Appendix

CVSS Score
6.1/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
EPSS Probability
0.34%
Top 72% most exploited

Affected Systems

Ruby on Rails (rails gem)Action View (actionview gem)

Affected Versions Detail

Product
Affected Versions
Fixed Version
actionview / rails
Ruby on Rails
>= 8.0.0.beta1, < 8.0.5.28.0.5.2
actionview / rails
Ruby on Rails
>= 8.1.0, < 8.1.4.18.1.4.1
AttributeDetail
CVE IDCVE-2026-126078
Advisory IDGHSA-v6rj-xm57-3p59
CWE ClassificationCWE-79 (Cross-Site Scripting)
CVSS v3.1 Score6.1 Medium (AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N)
EPSS Score0.34% (27.57th Percentile)
Affected ComponentActionView::Helpers::TextHelper#highlight
Patched VersionsRails 8.0.5.2, Rails 8.1.4.1
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1189Drive-by Compromise
Initial Access
T1185Browser Session Hijacking
Collection
CWE-79
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

The software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.

Vulnerability Timeline

Security patch authored by Mike Dalessio and Jeremy Daer in the Ruby on Rails repository
2026-10-31
Release preparation completed for Rails 8.1.4.1 and 8.0.5.2
2026-11-03
GitHub Security Advisory GHSA-v6rj-xm57-3p59 and CVE-2026-126078 officially published
2026-11-10
NVD CVSS v3.1 analysis and FIRST EPSS score published
2026-11-12

References & Sources

  • [1]GitHub Security Advisory GHSA-v6rj-xm57-3p59
  • [2]Official CVE.org Record for CVE-2026-126078
  • [3]NVD Vulnerability Detail: CVE-2026-126078
  • [4]Rails Fix Commit (8.1 / main branch) - 06938194b4fd59e1d2c8ab4a781f3c1e2b763425
  • [5]Rails Fix Commit (8.0 branch) - c796f6198837479ada13290eb8fa767b5219a58a
  • [6]Ruby on Rails Release v8.0.5.2
  • [7]Ruby on Rails Release v8.1.4.1
  • [8]CVEProject cvelistV5 Record for CVE-2026-126078

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

•about 1 hour ago•CVE-2026-126070
6.1

CVE-2026-126070: Cross-Site Scripting in Ruby on Rails Action View strip_tags Helper

CVE-2026-126070 is a Cross-Site Scripting (XSS) vulnerability in the Action View component of Ruby on Rails. Prior to versions 8.0.5.2 and 8.1.4.1, the strip_tags helper returned sanitized output marked as html_safe without encoding single or double quotation marks. When applications render the output of strip_tags inside quoted HTML attributes in ERB templates, attackers can break out of the attribute context and inject arbitrary HTML attributes or JavaScript event handlers.

Amit Schendel
Amit Schendel
2 views•10 min read
•about 3 hours ago•CVE-2026-126077
6.8

CVE-2026-126077: Session Information Leak in Ruby on Rails Action Pack and Active Storage Proxy Mode

An information exposure vulnerability in Ruby on Rails Action Pack allows sensitive session cookies to be attached to public, cacheable responses served by Active Storage proxy controllers. When cookie secret rotation or a hybrid cookie serializer migration is enabled, reading a legacy-format cookie triggers an automatic cookie rewrite that ignores the session-skipping directive. If an intermediate shared cache or CDN caches the resulting response along with its Set-Cookie header, subsequent users requesting the same URL receive the leaked session token.

Amit Schendel
Amit Schendel
3 views•11 min read
•about 4 hours ago•CVE-2026-126072
5.9

CVE-2026-126072: Thread Deadlock and Denial of Service in Ruby on Rails ActionController::Live

CVE-2026-126072 (GHSA-rwvh-fw6r-pwvp) is a concurrency deadlock vulnerability in the Ruby on Rails Action Pack framework affecting applications that utilize ActionController::Live response streaming. The defect occurs due to improper synchronization within ActionController::Live::Buffer when handling full bounded queues during stream closure and connection abortion. An unauthenticated remote attacker can trigger this condition by stalling TCP socket reads on streaming endpoints—including Active Storage proxy mode—resulting in permanent worker thread exhaustion and application-wide denial of service.

Amit Schendel
Amit Schendel
3 views•10 min read
•about 5 hours ago•CVE-2026-126192
6.3

CVE-2026-126192: Quadratic Algorithmic Complexity Denial of Service in Soup Sieve CSS Selector Engine

CVE-2026-126192 is an algorithmic complexity vulnerability in Soup Sieve (soupsieve), the default CSS selector engine for Beautiful Soup 4 in Python. Evaluating a CSS selector that contains a general sibling combinator (~) nested inside a :has() relational pseudo-class against attacker-controlled HTML markup triggers O(n^2) quadratic evaluation complexity when the right-hand sibling target is absent. An unauthenticated attacker can supply small HTML documents containing thousands of sibling elements to exhaust CPU resources and stall application worker threads.

Alon Barad
Alon Barad
2 views•10 min read
•about 6 hours ago•CVE-2026-126190
7.5

CVE-2026-126190: Polynomial-Time Denial of Service in Soup Sieve CSS Descendant Combinator

CVE-2026-126190 (GHSA-mmhr-3c5m-f64f) is an inefficient algorithmic complexity vulnerability (CWE-407) in Soup Sieve, the default CSS selector library integrated into Beautiful Soup 4. In versions prior to 4.0, evaluating CSS selectors that contain descendant combinators (whitespace between compound selectors) executes an unmemoized upward traversal of the document tree. When evaluated against deeply nested HTML or XML documents, the time complexity scales polynomially at O(n^(k+1)), where n is the tree depth and k is the number of descendant combinators. Remote attackers can supply compact, deeply nested markup (1 KB to 4 KB) to trigger prolonged CPU starvation and denial of service in Python applications.

Amit Schendel
Amit Schendel
3 views•9 min read
•about 7 hours ago•CVE-2026-122006
9.8

CVE-2026-122006: Unauthenticated Arbitrary File Read and Write in Ruby on Rails Active Storage via ImageMagick

CVE-2026-122006 is a critical vulnerability in the Ruby on Rails Active Storage framework affecting versions prior to 8.0.5.2 and 8.1.4.1. When an application processes uploaded file attachments using the ImageMagick variant processor (:mini_magick), the framework invokes ImageMagick's metadata analyzer without applying a restrictive security policy. An unauthenticated attacker can upload a crafted file containing directives for unrestricted ImageMagick coders, such as Magick Scripting Language (MSL), resulting in arbitrary server-side file read and write operations. In deployments using the Disk storage service, attackers can exfiltrate sensitive application configuration files, including secret_key_base and master encryption keys, which enables remote code execution via signed payload forgery.

Alon Barad
Alon Barad
3 views•10 min read