rails-html-sanitizer 1.3.0 → 1.4.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8eba1aac52c80be280f186c5d378150709b7d4cd2a5d5b2367e6d2c036648d52
4
- data.tar.gz: 96408eae2efee778a704f7caf246b64868a63bfdbbb81905b294bcca731a9289
3
+ metadata.gz: a74021096590326ee357971bec71d2c4507a95cdaf05c8e21d383ce18fee18d3
4
+ data.tar.gz: faad0d5f268dad601b633b03912e353fcc2d760fceb253d9cde2064b010b997a
5
5
  SHA512:
6
- metadata.gz: c4209cebc841299143a466143f4b776461fc1cc8bba112dc603e86835b68ee44a800566f64224b27f5a45d164d0b004049b228dc405c3de59068800ec7a5d564
7
- data.tar.gz: c899472b8dffe9f9fd4d15ae4739f07a775d74b9ed14143beb688bb546b6a82ec469add036747b81aff33510e6e241379e21458cb39d9b2a8e797824066e24e5
6
+ metadata.gz: e7f01438708076a283326c78b052ba954a42de4134d8d1d7e7c336c82ecd04c661f75dad3a0f9b1ffebe278f76ef229c98a3f2568801f82d94c94a50f399a2ef
7
+ data.tar.gz: 4f44c0e92eb9e565611772ba28d426025621c0517c4217004c3409192991a17498dd38165a6c55561a5347d2fcdf34f51b24101ad6de525604e35785e89efbc0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,81 @@
1
+ ## 1.4.4 / 2022-12-13
2
+
3
+ * Address inefficient regular expression complexity with certain configurations of Rails::Html::Sanitizer.
4
+
5
+ Fixes CVE-2022-23517. See
6
+ [GHSA-5x79-w82f-gw8w](https://github.com/rails/rails-html-sanitizer/security/advisories/GHSA-5x79-w82f-gw8w)
7
+ for more information.
8
+
9
+ *Mike Dalessio*
10
+
11
+ * Address improper sanitization of data URIs.
12
+
13
+ Fixes CVE-2022-23518 and #135. See
14
+ [GHSA-mcvf-2q2m-x72m](https://github.com/rails/rails-html-sanitizer/security/advisories/GHSA-mcvf-2q2m-x72m)
15
+ for more information.
16
+
17
+ *Mike Dalessio*
18
+
19
+ * Address possible XSS vulnerability with certain configurations of Rails::Html::Sanitizer.
20
+
21
+ Fixes CVE-2022-23520. See
22
+ [GHSA-rrfc-7g8p-99q8](https://github.com/rails/rails-html-sanitizer/security/advisories/GHSA-rrfc-7g8p-99q8)
23
+ for more information.
24
+
25
+ *Mike Dalessio*
26
+
27
+ * Address possible XSS vulnerability with certain configurations of Rails::Html::Sanitizer.
28
+
29
+ Fixes CVE-2022-23519. See
30
+ [GHSA-9h9g-93gc-623h](https://github.com/rails/rails-html-sanitizer/security/advisories/GHSA-9h9g-93gc-623h)
31
+ for more information.
32
+
33
+ *Mike Dalessio*
34
+
35
+
36
+ ## 1.4.3 / 2022-06-09
37
+
38
+ * Address a possible XSS vulnerability with certain configurations of Rails::Html::Sanitizer.
39
+
40
+ Prevent the combination of `select` and `style` as allowed tags in SafeListSanitizer.
41
+
42
+ Fixes CVE-2022-32209
43
+
44
+ *Mike Dalessio*
45
+
46
+
47
+ ## 1.4.2 / 2021-08-23
48
+
49
+ * Slightly improve performance.
50
+
51
+ Assuming elements are more common than comments, make one less method call per node.
52
+
53
+ *Mike Dalessio*
54
+
55
+ ## 1.4.1 / 2021-08-18
56
+
57
+ * Fix regression in v1.4.0 that did not pass comment nodes to the scrubber.
58
+
59
+ Some scrubbers will want to override the default behavior and allow comments, but v1.4.0 only
60
+ passed through elements to the scrubber's `keep_node?` method.
61
+
62
+ This change once again allows the scrubber to make the decision on comment nodes, but still skips
63
+ other non-elements like processing instructions (see #115).
64
+
65
+ *Mike Dalessio*
66
+
67
+ ## 1.4.0 / 2021-08-18
68
+
69
+ * Processing Instructions are no longer allowed by Rails::Html::PermitScrubber
70
+
71
+ Previously, a PI with a name (or "target") matching an allowed tag name was not scrubbed. There
72
+ are no known security issues associated with these PIs, but similar to comments it's preferred to
73
+ omit these nodes when possible from sanitized output.
74
+
75
+ Fixes #115.
76
+
77
+ *Mike Dalessio*
78
+
1
79
  ## 1.3.0
2
80
 
3
81
  * Address deprecations in Loofah 2.3.0.
data/README.md CHANGED
@@ -81,8 +81,10 @@ html_fragment.to_s # => "<a></a>"
81
81
  #### `Rails::Html::TargetScrubber`
82
82
 
83
83
  Where `PermitScrubber` picks out tags and attributes to permit in sanitization,
84
- `Rails::Html::TargetScrubber` targets them for removal.
84
+ `Rails::Html::TargetScrubber` targets them for removal. See https://github.com/flavorjones/loofah/blob/main/lib/loofah/html5/safelist.rb for the tag list.
85
85
 
86
+ **Note:** by default, it will scrub anything that is not part of the permitted tags from
87
+ loofah `HTML5::Scrub.allowed_element?`.
86
88
 
87
89
  ```ruby
88
90
  scrubber = Rails::Html::TargetScrubber.new
@@ -1,7 +1,7 @@
1
1
  module Rails
2
2
  module Html
3
3
  class Sanitizer
4
- VERSION = "1.3.0"
4
+ VERSION = "1.4.4"
5
5
  end
6
6
  end
7
7
  end
@@ -61,14 +61,14 @@ module Rails
61
61
  end
62
62
 
63
63
  def scrub(node)
64
- if node.cdata?
65
- text = node.document.create_text_node node.text
66
- node.replace text
64
+ if Loofah::HTML5::Scrub.cdata_needs_escaping?(node)
65
+ replacement = Loofah::HTML5::Scrub.cdata_escape(node)
66
+ node.replace(replacement)
67
67
  return CONTINUE
68
68
  end
69
69
  return CONTINUE if skip_node?(node)
70
70
 
71
- unless keep_node?(node)
71
+ unless (node.element? || node.comment?) && keep_node?(node)
72
72
  return STOP if scrub_node(node) == STOP
73
73
  end
74
74
 
@@ -139,15 +139,13 @@ module Rails
139
139
  end
140
140
 
141
141
  if Loofah::HTML5::SafeList::ATTR_VAL_IS_URI.include?(attr_name)
142
- # this block lifted nearly verbatim from HTML5 sanitization
143
- val_unescaped = CGI.unescapeHTML(attr_node.value).gsub(Loofah::HTML5::Scrub::CONTROL_CHARACTERS,'').downcase
144
- if val_unescaped =~ /^[a-z0-9][-+.a-z0-9]*:/ && ! Loofah::HTML5::SafeList::ALLOWED_PROTOCOLS.include?(val_unescaped.split(Loofah::HTML5::SafeList::PROTOCOL_SEPARATOR)[0])
145
- attr_node.remove
146
- end
142
+ return if Loofah::HTML5::Scrub.scrub_uri_attribute(attr_node)
147
143
  end
144
+
148
145
  if Loofah::HTML5::SafeList::SVG_ATTR_VAL_ALLOWS_REF.include?(attr_name)
149
- attr_node.value = attr_node.value.gsub(/url\s*\(\s*[^#\s][^)]+?\)/m, ' ') if attr_node.value
146
+ Loofah::HTML5::Scrub.scrub_attribute_that_allows_local_ref(attr_node)
150
147
  end
148
+
151
149
  if Loofah::HTML5::SafeList::SVG_ALLOW_LOCAL_HREF.include?(node.name) && attr_name == 'xlink:href' && attr_node.value =~ /^\s*[^#\s].*/m
152
150
  attr_node.remove
153
151
  end
@@ -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? ? %{&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_lt? ? %{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_lt_bang? ? %{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_lt_bang? ? %{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
@@ -93,7 +100,7 @@ class SanitizersTest < Minitest::Test
93
100
  end
94
101
 
95
102
  def test_strip_tags_with_plaintext
96
- assert_equal "Dont touch me", full_sanitize("Dont touch me")
103
+ assert_equal "Don't touch me", full_sanitize("Don't touch me")
97
104
  end
98
105
 
99
106
  def test_strip_tags_with_tags
@@ -135,7 +142,7 @@ class SanitizersTest < Minitest::Test
135
142
  end
136
143
 
137
144
  def test_strip_links_with_plaintext
138
- assert_equal "Dont touch me", link_sanitize("Dont touch me")
145
+ assert_equal "Don't touch me", link_sanitize("Don't touch me")
139
146
  end
140
147
 
141
148
  def test_strip_links_with_line_feed_and_uppercase_tag
@@ -271,7 +278,8 @@ class SanitizersTest < Minitest::Test
271
278
 
272
279
  def test_scrub_style_if_style_attribute_option_is_passed
273
280
  input = '<p style="color: #000; background-image: url(http://www.ragingplatypus.com/i/cam-full.jpg);"></p>'
274
- assert_equal '<p style="color: #000;"></p>', safe_list_sanitize(input, attributes: %w(style))
281
+ actual = safe_list_sanitize(input, attributes: %w(style))
282
+ assert_includes(['<p style="color: #000;"></p>', '<p style="color:#000;"></p>'], actual)
275
283
  end
276
284
 
277
285
  def test_should_raise_argument_error_if_tags_is_not_enumerable
@@ -413,8 +421,25 @@ class SanitizersTest < Minitest::Test
413
421
  end
414
422
 
415
423
  def test_should_sanitize_div_background_image_unicode_encoded
416
- raw = %(background-image:\0075\0072\006C\0028'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029'\0029)
417
- 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
418
443
  end
419
444
 
420
445
  def test_should_sanitize_div_style_expression
@@ -432,11 +457,15 @@ class SanitizersTest < Minitest::Test
432
457
  end
433
458
 
434
459
  def test_should_sanitize_cdata_section
435
- assert_sanitized "<![CDATA[<span>section</span>]]>", "section]]&gt;"
460
+ input = "<![CDATA[<span>section</span>]]>"
461
+ expected = libxml_2_9_14_recovery_lt_bang? ? %{&lt;![CDATA[<span>section</span>]]&gt;} : %{section]]&gt;}
462
+ assert_sanitized(input, expected)
436
463
  end
437
464
 
438
465
  def test_should_sanitize_unterminated_cdata_section
439
- assert_sanitized "<![CDATA[<span>neverending...", "neverending..."
466
+ input = "<![CDATA[<span>neverending..."
467
+ expected = libxml_2_9_14_recovery_lt_bang? ? %{&lt;![CDATA[<span>neverending...</span>} : %{neverending...}
468
+ assert_sanitized(input, expected)
440
469
  end
441
470
 
442
471
  def test_should_not_mangle_urls_with_ampersand
@@ -487,7 +516,13 @@ class SanitizersTest < Minitest::Test
487
516
 
488
517
  text = safe_list_sanitize(html)
489
518
 
490
- 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)
491
526
  end
492
527
 
493
528
  def test_uri_escaping_of_src_attr_in_a_tag_in_safe_list_sanitizer
@@ -497,7 +532,13 @@ class SanitizersTest < Minitest::Test
497
532
 
498
533
  text = safe_list_sanitize(html)
499
534
 
500
- 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)
501
542
  end
502
543
 
503
544
  def test_uri_escaping_of_name_attr_in_a_tag_in_safe_list_sanitizer
@@ -507,7 +548,13 @@ class SanitizersTest < Minitest::Test
507
548
 
508
549
  text = safe_list_sanitize(html)
509
550
 
510
- 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)
511
558
  end
512
559
 
513
560
  def test_uri_escaping_of_name_action_in_a_tag_in_safe_list_sanitizer
@@ -517,7 +564,141 @@ class SanitizersTest < Minitest::Test
517
564
 
518
565
  text = safe_list_sanitize(html, attributes: ['action'])
519
566
 
520
- 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)
574
+ end
575
+
576
+ def test_exclude_node_type_processing_instructions
577
+ assert_equal("<div>text</div><b>text</b>", safe_list_sanitize("<div>text</div><?div content><b>text</b>"))
578
+ end
579
+
580
+ def test_exclude_node_type_comment
581
+ assert_equal("<div>text</div><b>text</b>", safe_list_sanitize("<div>text</div><!-- comment --><b>text</b>"))
582
+ end
583
+
584
+ %w[text/plain text/css image/png image/gif image/jpeg].each do |mediatype|
585
+ define_method "test_mediatype_#{mediatype}_allowed" do
586
+ input = %Q(<img src="data:#{mediatype};base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">)
587
+ expected = input
588
+ actual = safe_list_sanitize(input)
589
+ assert_equal(expected, actual)
590
+
591
+ input = %Q(<img src="DATA:#{mediatype};base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">)
592
+ expected = input
593
+ actual = safe_list_sanitize(input)
594
+ assert_equal(expected, actual)
595
+ end
596
+ end
597
+
598
+ def test_mediatype_text_html_disallowed
599
+ input = %q(<img src="data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">)
600
+ expected = %q(<img>)
601
+ actual = safe_list_sanitize(input)
602
+ assert_equal(expected, actual)
603
+
604
+ input = %q(<img src="DATA:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">)
605
+ expected = %q(<img>)
606
+ actual = safe_list_sanitize(input)
607
+ assert_equal(expected, actual)
608
+ end
609
+
610
+ def test_mediatype_image_svg_xml_disallowed
611
+ input = %q(<img src="data:image/svg+xml;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">)
612
+ expected = %q(<img>)
613
+ actual = safe_list_sanitize(input)
614
+ assert_equal(expected, actual)
615
+
616
+ input = %q(<img src="DATA:image/svg+xml;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">)
617
+ expected = %q(<img>)
618
+ actual = safe_list_sanitize(input)
619
+ assert_equal(expected, actual)
620
+ end
621
+
622
+ def test_mediatype_other_disallowed
623
+ input = %q(<a href="data:foo;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">foo</a>)
624
+ expected = %q(<a>foo</a>)
625
+ actual = safe_list_sanitize(input)
626
+ assert_equal(expected, actual)
627
+
628
+ input = %q(<a href="DATA:foo;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">foo</a>)
629
+ expected = %q(<a>foo</a>)
630
+ actual = safe_list_sanitize(input)
631
+ assert_equal(expected, actual)
632
+ end
633
+
634
+ def test_scrubbing_svg_attr_values_that_allow_ref
635
+ input = %Q(<div fill="yellow url(http://bad.com/) #fff">hey</div>)
636
+ expected = %Q(<div fill="yellow #fff">hey</div>)
637
+ actual = scope_allowed_attributes %w(fill) do
638
+ safe_list_sanitize(input)
639
+ end
640
+
641
+ assert_equal(expected, actual)
642
+ end
643
+
644
+ def test_style_with_css_payload
645
+ input, tags = "<style>div > span { background: \"red\"; }</style>", ["style"]
646
+ expected = "<style>div &gt; span { background: \"red\"; }</style>"
647
+ actual = safe_list_sanitize(input, tags: tags)
648
+
649
+ assert_equal(expected, actual)
650
+ end
651
+
652
+ def test_combination_of_select_and_style_with_css_payload
653
+ input, tags = "<select><style>div > span { background: \"red\"; }</style></select>", ["select", "style"]
654
+ expected = "<select><style>div &gt; span { background: \"red\"; }</style></select>"
655
+ actual = safe_list_sanitize(input, tags: tags)
656
+
657
+ assert_equal(expected, actual)
658
+ end
659
+
660
+ def test_combination_of_select_and_style_with_script_payload
661
+ input, tags = "<select><style><script>alert(1)</script></style></select>", ["select", "style"]
662
+ expected = "<select><style>&lt;script&gt;alert(1)&lt;/script&gt;</style></select>"
663
+ actual = safe_list_sanitize(input, tags: tags)
664
+
665
+ assert_equal(expected, actual)
666
+ end
667
+
668
+ def test_combination_of_svg_and_style_with_script_payload
669
+ input, tags = "<svg><style><script>alert(1)</script></style></svg>", ["svg", "style"]
670
+ expected = "<svg><style>&lt;script&gt;alert(1)&lt;/script&gt;</style></svg>"
671
+ actual = safe_list_sanitize(input, tags: tags)
672
+
673
+ assert_equal(expected, actual)
674
+ end
675
+
676
+ def test_combination_of_math_and_style_with_img_payload
677
+ input, tags = "<math><style><img src=x onerror=alert(1)></style></math>", ["math", "style"]
678
+ expected = "<math><style>&lt;img src=x onerror=alert(1)&gt;</style></math>"
679
+ actual = safe_list_sanitize(input, tags: tags)
680
+
681
+ assert_equal(expected, actual)
682
+
683
+ input, tags = "<math><style><img src=x onerror=alert(1)></style></math>", ["math", "style", "img"]
684
+ expected = "<math><style>&lt;img src=x onerror=alert(1)&gt;</style></math>"
685
+ actual = safe_list_sanitize(input, tags: tags)
686
+
687
+ assert_equal(expected, actual)
688
+ end
689
+
690
+ def test_combination_of_svg_and_style_with_img_payload
691
+ input, tags = "<svg><style><img src=x onerror=alert(1)></style></svg>", ["svg", "style"]
692
+ expected = "<svg><style>&lt;img src=x onerror=alert(1)&gt;</style></svg>"
693
+ actual = safe_list_sanitize(input, tags: tags)
694
+
695
+ assert_equal(expected, actual)
696
+
697
+ input, tags = "<svg><style><img src=x onerror=alert(1)></style></svg>", ["svg", "style", "img"]
698
+ expected = "<svg><style>&lt;img src=x onerror=alert(1)&gt;</style></svg>"
699
+ actual = safe_list_sanitize(input, tags: tags)
700
+
701
+ assert_equal(expected, actual)
521
702
  end
522
703
 
523
704
  protected
@@ -565,4 +746,26 @@ protected
565
746
  ensure
566
747
  Rails::Html::SafeListSanitizer.allowed_attributes = old_attributes
567
748
  end
749
+
750
+ # note that this is used for testing CSS hex encoding: \\[0-9a-f]{1,6}
751
+ def convert_to_css_hex(string, escape_parens=false)
752
+ string.chars.map do |c|
753
+ if !escape_parens && (c == "(" || c == ")")
754
+ c
755
+ else
756
+ format('\00%02X', c.ord)
757
+ end
758
+ end.join
759
+ end
760
+
761
+ def libxml_2_9_14_recovery_lt?
762
+ # changed in 2.9.14, see https://github.com/sparklemotion/nokogiri/releases/tag/v1.13.5
763
+ Nokogiri.method(:uses_libxml?).arity == -1 && Nokogiri.uses_libxml?(">= 2.9.14")
764
+ end
765
+
766
+ def libxml_2_9_14_recovery_lt_bang?
767
+ # changed in 2.9.14, see https://github.com/sparklemotion/nokogiri/releases/tag/v1.13.5
768
+ # then reverted in 2.10.0, see https://gitlab.gnome.org/GNOME/libxml2/-/issues/380
769
+ Nokogiri.method(:uses_libxml?).arity == -1 && Nokogiri.uses_libxml?("= 2.9.14")
770
+ end
568
771
  end
@@ -41,6 +41,16 @@ class PermitScrubberTest < ScrubberTest
41
41
  assert_scrubbed '<tag>hello</tag>', 'hello'
42
42
  end
43
43
 
44
+ def test_default_scrub_removes_comments
45
+ assert_scrubbed('<div>one</div><!-- two --><span>three</span>',
46
+ '<div>one</div><span>three</span>')
47
+ end
48
+
49
+ def test_default_scrub_removes_processing_instructions
50
+ assert_scrubbed('<div>one</div><?div two><span>three</span>',
51
+ '<div>one</div><span>three</span>')
52
+ end
53
+
44
54
  def test_default_attributes_removal_behavior
45
55
  assert_scrubbed '<p cooler="hello">hello</p>', '<p>hello</p>'
46
56
  end
@@ -56,6 +66,12 @@ class PermitScrubberTest < ScrubberTest
56
66
  assert_scrubbed html, '<tag>leave me now</tag>'
57
67
  end
58
68
 
69
+ def test_leaves_comments_when_supplied_as_tag
70
+ @scrubber.tags = %w(div comment)
71
+ assert_scrubbed('<div>one</div><!-- two --><span>three</span>',
72
+ '<div>one</div><!-- two -->three')
73
+ end
74
+
59
75
  def test_leaves_only_supplied_tags_nested
60
76
  html = '<tag>leave <em>me <span>now</span></em></tag>'
61
77
  @scrubber.tags = %w(tag)
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.3.0
4
+ version: 1.4.4
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: 2019-10-06 00:00:00.000000000 Z
12
+ date: 2022-12-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: loofah
@@ -17,14 +17,20 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: '2.3'
20
+ version: '2.19'
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.19.1
21
24
  type: :runtime
22
25
  prerelease: false
23
26
  version_requirements: !ruby/object:Gem::Requirement
24
27
  requirements:
25
28
  - - "~>"
26
29
  - !ruby/object:Gem::Version
27
- version: '2.3'
30
+ version: '2.19'
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.19.1
28
34
  - !ruby/object:Gem::Dependency
29
35
  name: bundler
30
36
  requirement: !ruby/object:Gem::Requirement
@@ -101,7 +107,11 @@ files:
101
107
  homepage: https://github.com/rails/rails-html-sanitizer
102
108
  licenses:
103
109
  - MIT
104
- metadata: {}
110
+ metadata:
111
+ bug_tracker_uri: https://github.com/rails/rails-html-sanitizer/issues
112
+ changelog_uri: https://github.com/rails/rails-html-sanitizer/blob/v1.4.4/CHANGELOG.md
113
+ documentation_uri: https://www.rubydoc.info/gems/rails-html-sanitizer/1.4.4
114
+ source_code_uri: https://github.com/rails/rails-html-sanitizer/tree/v1.4.4
105
115
  post_install_message:
106
116
  rdoc_options: []
107
117
  require_paths:
@@ -117,10 +127,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
127
  - !ruby/object:Gem::Version
118
128
  version: '0'
119
129
  requirements: []
120
- rubygems_version: 3.0.3
130
+ rubygems_version: 3.3.7
121
131
  signing_key:
122
132
  specification_version: 4
123
133
  summary: This gem is responsible to sanitize HTML fragments in Rails applications.
124
134
  test_files:
125
- - test/scrubbers_test.rb
126
135
  - test/sanitizer_test.rb
136
+ - test/scrubbers_test.rb