CVE-2022-23517: Inefficient Regular Expression Complexity (CWE-1333)
value: rails-html-sanitizer is responsible for sanitizing HTML fragments in Rails applications. Certain configurations of rails-html-sanitizer < 1.4.4 use an inefficient regular expression that is susceptible to excessive backtracking when attempting to sanitize certain SVG attributes. This may lead to a denial of service through CPU resource consumption. This issue has been patched in version 1.4.4.
CWE description: The product uses a regular expression with an inefficient, possibly exponential worst-case computational complexity that consumes excessive CPU cycles.
CVSS v3 base score: 7.5
Published: 2022-12-14T17:15Z
Repository: https://github.com/rails/rails-html-sanitizer
Language: Ruby
Files changed: lib/rails/html/scrubbers.rb, test/sanitizer_test.rb
Commit date: 2022-12-13 09:19:34 -0500
Commit message: fix: replace slow regex attribute check with Loofah method

which uses the Crass parser

Diff: diff --git a/lib/rails/html/scrubbers.rb b/lib/rails/html/scrubbers.rb
index 13b6d6f..22327de 100644
--- a/lib/rails/html/scrubbers.rb
+++ b/lib/rails/html/scrubbers.rb
@@ -144,13 +144,15 @@ module Rails
           val_unescaped = CGI.unescapeHTML(attr_node.value).gsub(Loofah::HTML5::Scrub::CONTROL_CHARACTERS,'').downcase
           if val_unescaped =~ /^[a-z0-9][-+.a-z0-9]*:/ && ! Loofah::HTML5::SafeList::ALLOWED_PROTOCOLS.include?(val_unescaped.split(Loofah::HTML5::SafeList::PROTOCOL_SEPARATOR)[0])
             attr_node.remove
           end
         end
+
         if Loofah::HTML5::SafeList::SVG_ATTR_VAL_ALLOWS_REF.include?(attr_name)
-          attr_node.value = attr_node.value.gsub(/url\s*\(\s*[^#\s][^)]+?\)/m, ' ') if attr_node.value
+          Loofah::HTML5::Scrub.scrub_attribute_that_allows_local_ref(attr_node)
         end
+
         if Loofah::HTML5::SafeList::SVG_ALLOW_LOCAL_HREF.include?(node.name) && attr_name == 'xlink:href' && attr_node.value =~ /^\s*[^#\s].*/m
           attr_node.remove
         end
 
         node.remove_attribute(attr_node.name) if attr_name == 'src' && attr_node.value !~ /[^[:space:]]/
diff --git a/test/sanitizer_test.rb b/test/sanitizer_test.rb
index e83c54d..8784462 100644
--- a/test/sanitizer_test.rb
+++ b/test/sanitizer_test.rb
@@ -604,10 +604,20 @@ class SanitizersTest < Minitest::Test
       assert_output(nil, warning, &invocation)
     end
     refute_includes(sanitized, "style")
   end
 
+  def test_scrubbing_svg_attr_values_that_allow_ref
+    input = %Q(<div fill="yellow url(http://bad.com/) #fff">hey</div>)
+    expected = %Q(<div fill="yellow #fff">hey</div>)
+    actual = scope_allowed_attributes %w(fill) do
+      safe_list_sanitize(input)
+    end
+
+    assert_equal(expected, actual)
+  end
+
 protected
 
   def xpath_sanitize(input, options = {})
     XpathRemovalTestSanitizer.new.sanitize(input, options)
   end

Vulnerable code:           attr_node.value = attr_node.value.gsub(/url\s*\(\s*[^#\s][^)]+?\)/m, ' ') if attr_node.value
Fixed code: 
          Loofah::HTML5::Scrub.scrub_attribute_that_allows_local_ref(attr_node)

  def test_scrubbing_svg_attr_values_that_allow_ref
    input = %Q(<div fill="yellow url(http://bad.com/) #fff">hey</div>)
    expected = %Q(<div fill="yellow #fff">hey</div>)
    actual = scope_allowed_attributes %w(fill) do
      safe_list_sanitize(input)
    end

    assert_equal(expected, actual)
  end