rails-html-sanitizer 1.3.0 → 1.4.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +78 -0
- data/README.md +3 -1
- data/lib/rails/html/sanitizer/version.rb +1 -1
- data/lib/rails/html/scrubbers.rb +8 -10
- data/test/sanitizer_test.rb +222 -19
- data/test/scrubbers_test.rb +16 -0
- metadata +17 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a74021096590326ee357971bec71d2c4507a95cdaf05c8e21d383ce18fee18d3
|
4
|
+
data.tar.gz: faad0d5f268dad601b633b03912e353fcc2d760fceb253d9cde2064b010b997a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/lib/rails/html/scrubbers.rb
CHANGED
@@ -61,14 +61,14 @@ module Rails
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def scrub(node)
|
64
|
-
if
|
65
|
-
|
66
|
-
node.replace
|
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
|
-
|
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
|
-
|
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
|
data/test/sanitizer_test.rb
CHANGED
@@ -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
|
-
|
16
|
-
assert_equal '<script>alert("XSS");</script>', sanitizer.sanitize('<script><script></script>alert("XSS");<script><</script>/</script><script>script></script>', tags: %w(em))
|
17
|
+
assert_equal '<script>alert("XSS");</script>', 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
|
-
|
21
|
-
assert_equal '<script>alert("XSS");</script>', sanitizer.sanitize('<style><script></style>alert("XSS");<style><</style>/</style><style>script></style>', tags: %w(em))
|
21
|
+
assert_equal '<script>alert("XSS");</script>', 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
|
-
|
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
|
-
|
79
|
+
input = "This is <-- not\n a comment here."
|
80
|
+
expected = libxml_2_9_14_recovery_lt? ? %{This is <-- 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
|
-
|
85
|
+
input = "This has a <![CDATA[<section>]]> here."
|
86
|
+
expected = libxml_2_9_14_recovery_lt_bang? ? %{This has a <![CDATA[]]> here.} : %{This has a ]]> here.}
|
87
|
+
assert_equal(expected, full_sanitize(input))
|
83
88
|
end
|
84
89
|
|
85
90
|
def test_strip_unclosed_cdata
|
86
|
-
|
91
|
+
input = "This has an unclosed <![CDATA[<section>]] here..."
|
92
|
+
expected = libxml_2_9_14_recovery_lt_bang? ? %{This has an unclosed <![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 "
|
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 "
|
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
|
-
|
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
|
-
|
417
|
-
|
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
|
-
|
460
|
+
input = "<![CDATA[<span>section</span>]]>"
|
461
|
+
expected = libxml_2_9_14_recovery_lt_bang? ? %{<![CDATA[<span>section</span>]]>} : %{section]]>}
|
462
|
+
assert_sanitized(input, expected)
|
436
463
|
end
|
437
464
|
|
438
465
|
def test_should_sanitize_unterminated_cdata_section
|
439
|
-
|
466
|
+
input = "<![CDATA[<span>neverending..."
|
467
|
+
expected = libxml_2_9_14_recovery_lt_bang? ? %{<![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
|
-
|
519
|
+
acceptable_results = [
|
520
|
+
# nokogiri w/vendored+patched libxml2
|
521
|
+
%{<a href="examp<!--%22%20unsafeattr=foo()>-->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
|
-
|
535
|
+
acceptable_results = [
|
536
|
+
# nokogiri w/vendored+patched libxml2
|
537
|
+
%{<a src="examp<!--%22%20unsafeattr=foo()>-->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
|
-
|
551
|
+
acceptable_results = [
|
552
|
+
# nokogiri w/vendored+patched libxml2
|
553
|
+
%{<a name="examp<!--%22%20unsafeattr=foo()>-->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
|
-
|
567
|
+
acceptable_results = [
|
568
|
+
# nokogiri w/vendored+patched libxml2
|
569
|
+
%{<a action="examp<!--%22%20unsafeattr=foo()>-->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 > 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 > 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><script>alert(1)</script></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><script>alert(1)</script></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><img src=x onerror=alert(1)></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><img src=x onerror=alert(1)></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><img src=x onerror=alert(1)></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><img src=x onerror=alert(1)></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
|
data/test/scrubbers_test.rb
CHANGED
@@ -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.
|
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:
|
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.
|
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.
|
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.
|
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
|