CVE-2018-3741: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: There is a possible XSS vulnerability in all rails-html-sanitizer gem versions below 1.0.4 for Ruby. The gem allows non-whitelisted attributes to be present in sanitized output when input with specially-crafted HTML fragments, and these attributes can lead to an XSS attack on target applications. This issue is similar to CVE-2018-8048 in Loofah. All users running an affected release should either upgrade or use one of the workarounds immediately.
CWE description: The product 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.
CVSS v3 base score: 6.1
Published: 2018-03-30T19:29Z
Repository: https://github.com/rails/rails-html-sanitizer
Language: Ruby
Files changed: lib/rails/html/scrubbers.rb, rails-html-sanitizer.gemspec, test/sanitizer_test.rb
Commit date: 2018-03-22 14:54:31 -0400
Commit message: Make sure we address CVE-2018-8048

Even that the issue was fixed on loofah we have our own logic to scrub
attributes so when the whitelist serializer is used the issue was still
present.

Fix CVE-2018-3741.

Diff: diff --git a/lib/rails/html/scrubbers.rb b/lib/rails/html/scrubbers.rb
index 57c4034..42436f4 100644
--- a/lib/rails/html/scrubbers.rb
+++ b/lib/rails/html/scrubbers.rb
@@ -151,10 +151,12 @@ module Rails
         if Loofah::HTML5::WhiteList::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:]]/
+
+        Loofah::HTML5::Scrub.force_correct_attribute_escaping! node
       end
     end
 
     # === Rails::Html::TargetScrubber
     #
diff --git a/rails-html-sanitizer.gemspec b/rails-html-sanitizer.gemspec
index 698ff4b..e774244 100644
--- a/rails-html-sanitizer.gemspec
+++ b/rails-html-sanitizer.gemspec
@@ -15,11 +15,11 @@ Gem::Specification.new do |spec|
 
   spec.files         = Dir["lib/**/*", "README.md", "MIT-LICENSE", "CHANGELOG.md"]
   spec.test_files    = Dir["test/**/*"]
   spec.require_paths = ["lib"]
 
-  spec.add_dependency "loofah", "~> 2.0"
+  spec.add_dependency "loofah", "~> 2.2", ">= 2.2.2"
 
   spec.add_development_dependency "bundler", "~> 1.3"
   spec.add_development_dependency "rake"
   spec.add_development_dependency "minitest"
   spec.add_development_dependency "rails-dom-testing"
diff --git a/test/sanitizer_test.rb b/test/sanitizer_test.rb
index 9651c94..7bcab6f 100644
--- a/test/sanitizer_test.rb
+++ b/test/sanitizer_test.rb
@@ -383,17 +383,17 @@ class SanitizersTest < Minitest::Test
     assert_sanitized %(<SPAN title="'><script>alert()</script>">blah</SPAN>), %(<span title="#{CGI.escapeHTML "'><script>alert()</script>"}">blah</span>)
   end
 
   def test_should_sanitize_illegal_style_properties
     raw      = %(display:block; position:absolute; left:0; top:0; width:100%; height:100%; z-index:1; background-color:black; background-image:url(http://www.ragingplatypus.com/i/cam-full.jpg); background-x:center; background-y:center; background-repeat:repeat;)
-    expected = %(display: block; width: 100%; height: 100%; background-color: black; background-x: center; background-y: center;)
+    expected = %(display:block;width:100%;height:100%;background-color:black;background-x:center;background-y:center;)
     assert_equal expected, sanitize_css(raw)
   end
 
   def test_should_sanitize_with_trailing_space
     raw = "display:block; "
-    expected = "display: block;"
+    expected = "display:block;"
     assert_equal expected, sanitize_css(raw)
   end
 
   def test_should_sanitize_xul_style_attributes
     raw = %(-moz-binding:url('http://ha.ckers.org/xssmoz.xml#xss'))
@@ -482,10 +482,42 @@ class SanitizersTest < Minitest::Test
   def test_allow_data_attribute_if_requested
     text = %(<a data-foo="foo">foo</a>)
     assert_equal %(<a data-foo="foo">foo</a>), white_list_sanitize(text, attributes: ['data-foo'])
   end
 
+  def test_uri_escaping_of_href_attr_in_a_tag_in_white_list_sanitizer
+    html = %{<a href='examp<!--" unsafeattr=foo()>-->le.com'>test</a>}
+
+    text = white_list_sanitize(html)
+
+    assert_equal %{<a href="examp<!--%22%20unsafeattr=foo()>-->le.com">test</a>}, text
+  end
+
+  def test_uri_escaping_of_src_attr_in_a_tag_in_white_list_sanitizer
+    html = %{<a src='examp<!--" unsafeattr=foo()>-->le.com'>test</a>}
+
+    text = white_list_sanitize(html)
+
+    assert_equal %{<a src="examp<!--%22%20unsafeattr=foo()>-->le.com">test</a>}, text
+  end
+
+  def test_uri_escaping_of_name_attr_in_a_tag_in_white_list_sanitizer
+    html = %{<a name='examp<!--" unsafeattr=foo()>-->le.com'>test</a>}
+
+    text = white_list_sanitize(html)
+
+    assert_equal %{<a name="examp<!--%22%20unsafeattr=foo()>-->le.com">test</a>}, text
+  end
+
+  def test_uri_escaping_of_name_action_in_a_tag_in_white_list_sanitizer
+    html = %{<a action='examp<!--" unsafeattr=foo()>-->le.com'>test</a>}
+
+    text = white_list_sanitize(html, attributes: ['action'])
+
+    assert_equal %{<a action="examp<!--%22%20unsafeattr=foo()>-->le.com">test</a>}, text
+  end
+
 protected
 
   def xpath_sanitize(input, options = {})
     XpathRemovalTestSanitizer.new.sanitize(input, options)
   end

Vulnerable code:   spec.add_dependency "loofah", "~> 2.0"
    expected = %(display: block; width: 100%; height: 100%; background-color: black; background-x: center; background-y: center;)
    expected = "display: block;"
Fixed code: 
        Loofah::HTML5::Scrub.force_correct_attribute_escaping! node
  spec.add_dependency "loofah", "~> 2.2", ">= 2.2.2"
    expected = %(display:block;width:100%;height:100%;background-color:black;background-x:center;background-y:center;)
    expected = "display:block;"
  def test_uri_escaping_of_href_attr_in_a_tag_in_white_list_sanitizer
    html = %{<a href='examp<!--" unsafeattr=foo()>-->le.com'>test</a>}

    text = white_list_sanitize(html)

    assert_equal %{<a href="examp<!--%22%20unsafeattr=foo()>-->le.com">test</a>}, text
  end

  def test_uri_escaping_of_src_attr_in_a_tag_in_white_list_sanitizer
    html = %{<a src='examp<!--" unsafeattr=foo()>-->le.com'>test</a>}

    text = white_list_sanitize(html)

    assert_equal %{<a src="examp<!--%22%20unsafeattr=foo()>-->le.com">test</a>}, text
  end

  def test_uri_escaping_of_name_attr_in_a_tag_in_white_list_sanitizer
    html = %{<a name='examp<!--" unsafeattr=foo()>-->le.com'>test</a>}

    text = white_list_sanitize(html)

    assert_equal %{<a name="examp<!--%22%20unsafeattr=foo()>-->le.com">test</a>}, text
  end

  def test_uri_escaping_of_name_action_in_a_tag_in_white_list_sanitizer
    html = %{<a action='examp<!--" unsafeattr=foo()>-->le.com'>test</a>}

    text = white_list_sanitize(html, attributes: ['action'])

    assert_equal %{<a action="examp<!--%22%20unsafeattr=foo()>-->le.com">test</a>}, text
  end