rails-html-sanitizer 1.4.2 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of rails-html-sanitizer might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 85be608ca4422813683df971eb55217f0a70d9bb3d6398efad913ddb90d2c3c5
4
- data.tar.gz: cdc86ec92f2698f49d73d37e58622b97f4115330e084a2bc6ea46fc711926e94
3
+ metadata.gz: 2f00d9f256478eb753c8d211c3b25efa4204bbdbc9c5abf0415413c811a2e404
4
+ data.tar.gz: 65d3871aa798dfbbfb1138b666d475b590e347cdb66614d6d39b72ad3531c742
5
5
  SHA512:
6
- metadata.gz: b748cab99a7c9bdda776b5aaf76a55e16ff59b6aa10f4ee1fd9b97b7f5a6a897a8a2e0e1fe31cdd741207130d34ccdff2debb4437b0b03b87896ab9c16537f4b
7
- data.tar.gz: 35f4c0c12c555feb73623df3bc09d19069c48b9ee91539dc247b6a599dc091adb08b56f43041014dfacd6f46183f7b6d68355104716a1feeaef58c3319be6bea
6
+ metadata.gz: e6e31eaa72b1a2e8356aae50600ac784f85a80828cbc49ce8061384ecd3f21a1d8eaee69845dc08537c5102728c3cc41a72cb3ed8b9789c4921038398afa61e2
7
+ data.tar.gz: 6b14a49842eaf4c3e0fbae5acd28fdf32a5deb6cd42f769aada848226847180c4d3a67a9dcbc439e1a4855699b0ea694cb4c7b6ee173391ac841bd334ae44b6f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## 1.4.3 / 2022-06-09
2
+
3
+ * Address a possible XSS vulnerability with certain configurations of Rails::Html::Sanitizer.
4
+
5
+ Prevent the combination of `select` and `style` as allowed tags in SafeListSanitizer.
6
+
7
+ Fixes CVE-2022-32209
8
+
9
+ *Mike Dalessio*
10
+
11
+
1
12
  ## 1.4.2 / 2021-08-23
2
13
 
3
14
  * Slightly improve performance.
@@ -1,7 +1,7 @@
1
1
  module Rails
2
2
  module Html
3
3
  class Sanitizer
4
- VERSION = "1.4.2"
4
+ VERSION = "1.4.3"
5
5
  end
6
6
  end
7
7
  end
@@ -141,8 +141,25 @@ module Rails
141
141
 
142
142
  private
143
143
 
144
+ def loofah_using_html5?
145
+ # future-proofing, see https://github.com/flavorjones/loofah/pull/239
146
+ Loofah.respond_to?(:html5_mode?) && Loofah.html5_mode?
147
+ end
148
+
149
+ def remove_safelist_tag_combinations(tags)
150
+ if !loofah_using_html5? && tags.include?("select") && tags.include?("style")
151
+ warn("WARNING: #{self.class}: removing 'style' from safelist, should not be combined with 'select'")
152
+ tags.delete("style")
153
+ end
154
+ tags
155
+ end
156
+
144
157
  def allowed_tags(options)
145
- options[:tags] || self.class.allowed_tags
158
+ if options[:tags]
159
+ remove_safelist_tag_combinations(options[:tags])
160
+ else
161
+ self.class.allowed_tags
162
+ end
146
163
  end
147
164
 
148
165
  def allowed_attributes(options)
@@ -2,6 +2,8 @@ require "minitest/autorun"
2
2
  require "rails-html-sanitizer"
3
3
  require "rails/dom/testing/assertions/dom_assertions"
4
4
 
5
+ puts Nokogiri::VERSION_INFO
6
+
5
7
  class SanitizersTest < Minitest::Test
6
8
  include Rails::Dom::Testing::Assertions::DomAssertions
7
9
 
@@ -12,13 +14,11 @@ class SanitizersTest < Minitest::Test
12
14
  end
13
15
 
14
16
  def test_sanitize_nested_script
15
- sanitizer = Rails::Html::SafeListSanitizer.new
16
- assert_equal '&lt;script&gt;alert("XSS");&lt;/script&gt;', sanitizer.sanitize('<script><script></script>alert("XSS");<script><</script>/</script><script>script></script>', tags: %w(em))
17
+ assert_equal '&lt;script&gt;alert("XSS");&lt;/script&gt;', safe_list_sanitize('<script><script></script>alert("XSS");<script><</script>/</script><script>script></script>', tags: %w(em))
17
18
  end
18
19
 
19
20
  def test_sanitize_nested_script_in_style
20
- sanitizer = Rails::Html::SafeListSanitizer.new
21
- assert_equal '&lt;script&gt;alert("XSS");&lt;/script&gt;', sanitizer.sanitize('<style><script></style>alert("XSS");<style><</style>/</style><style>script></style>', tags: %w(em))
21
+ assert_equal '&lt;script&gt;alert("XSS");&lt;/script&gt;', safe_list_sanitize('<style><script></style>alert("XSS");<style><</style>/</style><style>script></style>', tags: %w(em))
22
22
  end
23
23
 
24
24
  class XpathRemovalTestSanitizer < Rails::Html::Sanitizer
@@ -54,7 +54,8 @@ class SanitizersTest < Minitest::Test
54
54
 
55
55
  def test_strip_tags_with_quote
56
56
  input = '<" <img src="trollface.gif" onload="alert(1)"> hi'
57
- assert_equal ' hi', full_sanitize(input)
57
+ expected = libxml_2_9_14_recovery? ? %{&lt;" hi} : %{ hi}
58
+ assert_equal(expected, full_sanitize(input))
58
59
  end
59
60
 
60
61
  def test_strip_invalid_html
@@ -75,15 +76,21 @@ class SanitizersTest < Minitest::Test
75
76
  end
76
77
 
77
78
  def test_remove_unclosed_tags
78
- assert_equal "This is ", full_sanitize("This is <-- not\n a comment here.")
79
+ input = "This is <-- not\n a comment here."
80
+ expected = libxml_2_9_14_recovery? ? %{This is &lt;-- not\n a comment here.} : %{This is }
81
+ assert_equal(expected, full_sanitize(input))
79
82
  end
80
83
 
81
84
  def test_strip_cdata
82
- assert_equal "This has a ]]&gt; here.", full_sanitize("This has a <![CDATA[<section>]]> here.")
85
+ input = "This has a <![CDATA[<section>]]> here."
86
+ expected = libxml_2_9_14_recovery? ? %{This has a &lt;![CDATA[]]&gt; here.} : %{This has a ]]&gt; here.}
87
+ assert_equal(expected, full_sanitize(input))
83
88
  end
84
89
 
85
90
  def test_strip_unclosed_cdata
86
- assert_equal "This has an unclosed ]] here...", full_sanitize("This has an unclosed <![CDATA[<section>]] here...")
91
+ input = "This has an unclosed <![CDATA[<section>]] here..."
92
+ expected = libxml_2_9_14_recovery? ? %{This has an unclosed &lt;![CDATA[]] here...} : %{This has an unclosed ]] here...}
93
+ assert_equal(expected, full_sanitize(input))
87
94
  end
88
95
 
89
96
  def test_strip_blank_string
@@ -414,8 +421,25 @@ class SanitizersTest < Minitest::Test
414
421
  end
415
422
 
416
423
  def test_should_sanitize_div_background_image_unicode_encoded
417
- raw = %(background-image:\u0075\u0072\u006C\u0028\u0027\u006a\u0061\u0076\u0061\u0073\u0063\u0072\u0069\u0070\u0074\u003a\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0032\u0033\u0034\u0029\u0027\u0029)
418
- assert_equal '', sanitize_css(raw)
424
+ [
425
+ convert_to_css_hex("url(javascript:alert(1))", false),
426
+ convert_to_css_hex("url(javascript:alert(1))", true),
427
+ convert_to_css_hex("url(https://example.com)", false),
428
+ convert_to_css_hex("url(https://example.com)", true),
429
+ ].each do |propval|
430
+ raw = "background-image:" + propval
431
+ assert_empty(sanitize_css(raw))
432
+ end
433
+ end
434
+
435
+ def test_should_allow_div_background_image_unicode_encoded_safe_functions
436
+ [
437
+ convert_to_css_hex("rgb(255,0,0)", false),
438
+ convert_to_css_hex("rgb(255,0,0)", true),
439
+ ].each do |propval|
440
+ raw = "background-image:" + propval
441
+ assert_includes(sanitize_css(raw), "background-image")
442
+ end
419
443
  end
420
444
 
421
445
  def test_should_sanitize_div_style_expression
@@ -433,11 +457,15 @@ class SanitizersTest < Minitest::Test
433
457
  end
434
458
 
435
459
  def test_should_sanitize_cdata_section
436
- assert_sanitized "<![CDATA[<span>section</span>]]>", "section]]&gt;"
460
+ input = "<![CDATA[<span>section</span>]]>"
461
+ expected = libxml_2_9_14_recovery? ? %{&lt;![CDATA[<span>section</span>]]&gt;} : %{section]]&gt;}
462
+ assert_sanitized(input, expected)
437
463
  end
438
464
 
439
465
  def test_should_sanitize_unterminated_cdata_section
440
- assert_sanitized "<![CDATA[<span>neverending...", "neverending..."
466
+ input = "<![CDATA[<span>neverending..."
467
+ expected = libxml_2_9_14_recovery? ? %{&lt;![CDATA[<span>neverending...</span>} : %{neverending...}
468
+ assert_sanitized(input, expected)
441
469
  end
442
470
 
443
471
  def test_should_not_mangle_urls_with_ampersand
@@ -488,7 +516,13 @@ class SanitizersTest < Minitest::Test
488
516
 
489
517
  text = safe_list_sanitize(html)
490
518
 
491
- assert_equal %{<a href=\"examp&lt;!--%22%20unsafeattr=foo()&gt;--&gt;le.com\">test</a>}, text
519
+ acceptable_results = [
520
+ # nokogiri w/vendored+patched libxml2
521
+ %{<a href="examp&lt;!--%22%20unsafeattr=foo()&gt;--&gt;le.com">test</a>},
522
+ # nokogiri w/ system libxml2
523
+ %{<a href="examp<!--%22%20unsafeattr=foo()>-->le.com">test</a>},
524
+ ]
525
+ assert_includes(acceptable_results, text)
492
526
  end
493
527
 
494
528
  def test_uri_escaping_of_src_attr_in_a_tag_in_safe_list_sanitizer
@@ -498,7 +532,13 @@ class SanitizersTest < Minitest::Test
498
532
 
499
533
  text = safe_list_sanitize(html)
500
534
 
501
- assert_equal %{<a src=\"examp&lt;!--%22%20unsafeattr=foo()&gt;--&gt;le.com\">test</a>}, text
535
+ acceptable_results = [
536
+ # nokogiri w/vendored+patched libxml2
537
+ %{<a src="examp&lt;!--%22%20unsafeattr=foo()&gt;--&gt;le.com">test</a>},
538
+ # nokogiri w/system libxml2
539
+ %{<a src="examp<!--%22%20unsafeattr=foo()>-->le.com">test</a>},
540
+ ]
541
+ assert_includes(acceptable_results, text)
502
542
  end
503
543
 
504
544
  def test_uri_escaping_of_name_attr_in_a_tag_in_safe_list_sanitizer
@@ -508,7 +548,13 @@ class SanitizersTest < Minitest::Test
508
548
 
509
549
  text = safe_list_sanitize(html)
510
550
 
511
- assert_equal %{<a name=\"examp&lt;!--%22%20unsafeattr=foo()&gt;--&gt;le.com\">test</a>}, text
551
+ acceptable_results = [
552
+ # nokogiri w/vendored+patched libxml2
553
+ %{<a name="examp&lt;!--%22%20unsafeattr=foo()&gt;--&gt;le.com">test</a>},
554
+ # nokogiri w/system libxml2
555
+ %{<a name="examp<!--%22%20unsafeattr=foo()>-->le.com">test</a>},
556
+ ]
557
+ assert_includes(acceptable_results, text)
512
558
  end
513
559
 
514
560
  def test_uri_escaping_of_name_action_in_a_tag_in_safe_list_sanitizer
@@ -518,7 +564,13 @@ class SanitizersTest < Minitest::Test
518
564
 
519
565
  text = safe_list_sanitize(html, attributes: ['action'])
520
566
 
521
- assert_equal %{<a action=\"examp&lt;!--%22%20unsafeattr=foo()&gt;--&gt;le.com\">test</a>}, text
567
+ acceptable_results = [
568
+ # nokogiri w/vendored+patched libxml2
569
+ %{<a action="examp&lt;!--%22%20unsafeattr=foo()&gt;--&gt;le.com">test</a>},
570
+ # nokogiri w/system libxml2
571
+ %{<a action="examp<!--%22%20unsafeattr=foo()>-->le.com">test</a>},
572
+ ]
573
+ assert_includes(acceptable_results, text)
522
574
  end
523
575
 
524
576
  def test_exclude_node_type_processing_instructions
@@ -529,6 +581,25 @@ class SanitizersTest < Minitest::Test
529
581
  assert_equal("<div>text</div><b>text</b>", safe_list_sanitize("<div>text</div><!-- comment --><b>text</b>"))
530
582
  end
531
583
 
584
+ def test_disallow_the_dangerous_safelist_combination_of_select_and_style
585
+ input = "<select><style><script>alert(1)</script></style></select>"
586
+ tags = ["select", "style"]
587
+ warning = /WARNING: Rails::Html::SafeListSanitizer: removing 'style' from safelist/
588
+ sanitized = nil
589
+ invocation = Proc.new { sanitized = safe_list_sanitize(input, tags: tags) }
590
+
591
+ if html5_mode?
592
+ # if Loofah is using an HTML5 parser,
593
+ # then "style" should be removed by the parser as an invalid child of "select"
594
+ assert_silent(&invocation)
595
+ else
596
+ # if Loofah is using an HTML4 parser,
597
+ # then SafeListSanitizer should remove "style" from the safelist
598
+ assert_output(nil, warning, &invocation)
599
+ end
600
+ refute_includes(sanitized, "style")
601
+ end
602
+
532
603
  protected
533
604
 
534
605
  def xpath_sanitize(input, options = {})
@@ -574,4 +645,23 @@ protected
574
645
  ensure
575
646
  Rails::Html::SafeListSanitizer.allowed_attributes = old_attributes
576
647
  end
648
+
649
+ # note that this is used for testing CSS hex encoding: \\[0-9a-f]{1,6}
650
+ def convert_to_css_hex(string, escape_parens=false)
651
+ string.chars.map do |c|
652
+ if !escape_parens && (c == "(" || c == ")")
653
+ c
654
+ else
655
+ format('\00%02X', c.ord)
656
+ end
657
+ end.join
658
+ end
659
+
660
+ def libxml_2_9_14_recovery?
661
+ Nokogiri.method(:uses_libxml?).arity == -1 && Nokogiri.uses_libxml?(">= 2.9.14")
662
+ end
663
+
664
+ def html5_mode?
665
+ ::Loofah.respond_to?(:html5_mode?) && ::Loofah.html5_mode?
666
+ end
577
667
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-html-sanitizer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.2
4
+ version: 1.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rafael Mendonça França
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-08-24 00:00:00.000000000 Z
12
+ date: 2022-06-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: loofah
@@ -103,9 +103,9 @@ licenses:
103
103
  - MIT
104
104
  metadata:
105
105
  bug_tracker_uri: https://github.com/rails/rails-html-sanitizer/issues
106
- changelog_uri: https://github.com/rails/rails-html-sanitizer/blob/v1.4.2/CHANGELOG.md
107
- documentation_uri: https://www.rubydoc.info/gems/rails-html-sanitizer/1.4.2
108
- source_code_uri: https://github.com/rails/rails-html-sanitizer/tree/v1.4.2
106
+ changelog_uri: https://github.com/rails/rails-html-sanitizer/blob/v1.4.3/CHANGELOG.md
107
+ documentation_uri: https://www.rubydoc.info/gems/rails-html-sanitizer/1.4.3
108
+ source_code_uri: https://github.com/rails/rails-html-sanitizer/tree/v1.4.3
109
109
  post_install_message:
110
110
  rdoc_options: []
111
111
  require_paths:
@@ -121,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
121
  - !ruby/object:Gem::Version
122
122
  version: '0'
123
123
  requirements: []
124
- rubygems_version: 3.2.15
124
+ rubygems_version: 3.3.5
125
125
  signing_key:
126
126
  specification_version: 4
127
127
  summary: This gem is responsible to sanitize HTML fragments in Rails applications.