VYPR
Moderate severityNVD Advisory· Published Oct 28, 2024· Updated Nov 3, 2025

REXML ReDoS vulnerability

CVE-2024-49761

Description

REXML is an XML toolkit for Ruby. The REXML gem before 3.3.9 has a ReDoS vulnerability when it parses an XML that has many digits between &# and x...; in a hex numeric character reference (&#x...;). This does not happen with Ruby 3.2 or later. Ruby 3.1 is the only affected maintained Ruby. The REXML gem 3.3.9 or later include the patch to fix the vulnerability.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

REXML gem before 3.3.9 has a ReDoS vulnerability via hex numeric character references with leading zeros in XML parsing, affecting Ruby 3.1.

CVE-2024-49761 is a Regular Expression Denial-of-Service (ReDoS) vulnerability in the REXML XML toolkit for Ruby. The flaw resides in the regular expression used to match hex numeric character references (&#x...;). The pattern CHARACTER_REFERENCES = /&#0*((?: +)|(?:x[a-fA-F0-9]+));/ accepts an arbitrary number of leading zeros before the hex digits, causing exponential backtracking when parsing a crafted XML document with many leading zeros [1].

The vulnerability is exploitable by supplying a specially crafted XML document containing a hex numeric character reference with a large number of leading zeros (e.g., &#x000...0;). Parsing such input triggers catastrophic backtracking in the regex engine, consuming excessive CPU resources. The attack does not require authentication; any application using the affected REXML gem to parse untrusted XML data is at risk. Note that Ruby 3.2 and later use an updated regex engine that is not susceptible to this issue; therefore, Ruby 3.1 is the only maintained Ruby version impacted [1][3].

Successful exploitation leads to a denial-of-service condition. An attacker can cause the XML parser to hang or become extremely slow, potentially making the application unresponsive. This can be leveraged to exhaust server resources and disrupt availability. The CVSS base score is 5.3 (Medium), with the attack vector being network-based and requiring no privileges [1].

The vulnerability has been patched in REXML gem version 3.3.9. The fix, visible in commit ce59f2eb1aeb371fe1643414f06618dbe031979f, modifies the CHARACTER_REFERENCES regex to disallow leading zeros and updates the unnormalize method to correctly handle the character reference format [4]. Users running Ruby 3.1 should upgrade the rexml gem to 3.3.9 or later. Users on other Ruby versions should ensure their REXML gem is up to date. No workaround is available besides updating [1][3].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
rexmlRubyGems
< 3.3.93.3.9

Affected products

145

Patches

1
ce59f2eb1aeb

parser: fix a bug that &#0x...; is accepted as a character reference

https://github.com/ruby/rexmlSutou KouheiOct 24, 2024via ghsa
2 files changed · +13 3
  • lib/rexml/parsers/baseparser.rb+7 3 modified
    @@ -150,7 +150,7 @@ module Private
             PEDECL_PATTERN = "\\s+(%)\\s+#{NAME}\\s+#{PEDEF}\\s*>"
             ENTITYDECL_PATTERN = /(?:#{GEDECL_PATTERN})|(?:#{PEDECL_PATTERN})/um
             CARRIAGE_RETURN_NEWLINE_PATTERN = /\r\n?/
    -        CHARACTER_REFERENCES = /&#0*((?:\d+)|(?:x[a-fA-F0-9]+));/
    +        CHARACTER_REFERENCES = /&#((?:\d+)|(?:x[a-fA-F0-9]+));/
             DEFAULT_ENTITIES_PATTERNS = {}
             default_entities = ['gt', 'lt', 'quot', 'apos', 'amp']
             default_entities.each do |term|
    @@ -570,8 +570,12 @@ def unnormalize( string, entities=nil, filter=nil )
             return rv if matches.size == 0
             rv.gsub!( Private::CHARACTER_REFERENCES ) {
               m=$1
    -          m = "0#{m}" if m[0] == ?x
    -          [Integer(m)].pack('U*')
    +          if m.start_with?("x")
    +            code_point = Integer(m[1..-1], 16)
    +          else
    +            code_point = Integer(m, 10)
    +          end
    +          [code_point].pack('U*')
             }
             matches.collect!{|x|x[0]}.compact!
             if filter
    
  • test/parse/test_character_reference.rb+6 0 modified
    @@ -13,5 +13,11 @@ def test_linear_performance_many_preceding_zeros
             REXML::Document.new('<test testing="&#' + "0" * n + '97;"/>')
           end
         end
    +
    +    def test_hex_precedding_zero
    +      parser = REXML::Parsers::PullParser.new("<root>&#x61;&#0x61;</root>")
    +      parser.pull # :start_element
    +      assert_equal("a&#0x61;", parser.pull[1]) # :text
    +    end
       end
     end
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

8

News mentions

0

No linked articles in our index yet.