rails-html-sanitizer 1.4.3 → 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 +35 -0
- data/lib/rails/html/sanitizer/version.rb +1 -1
- data/lib/rails/html/sanitizer.rb +1 -18
- data/lib/rails/html/scrubbers.rb +7 -9
- data/test/sanitizer_test.rb +128 -24
- metadata +14 -8
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,38 @@
|
|
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
|
+
|
1
36
|
## 1.4.3 / 2022-06-09
|
2
37
|
|
3
38
|
* Address a possible XSS vulnerability with certain configurations of Rails::Html::Sanitizer.
|
data/lib/rails/html/sanitizer.rb
CHANGED
@@ -141,25 +141,8 @@ 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
|
-
|
157
144
|
def allowed_tags(options)
|
158
|
-
|
159
|
-
remove_safelist_tag_combinations(options[:tags])
|
160
|
-
else
|
161
|
-
self.class.allowed_tags
|
162
|
-
end
|
145
|
+
options[:tags] || self.class.allowed_tags
|
163
146
|
end
|
164
147
|
|
165
148
|
def allowed_attributes(options)
|
data/lib/rails/html/scrubbers.rb
CHANGED
@@ -61,9 +61,9 @@ 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)
|
@@ -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
@@ -54,7 +54,7 @@ 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
|
-
expected =
|
57
|
+
expected = libxml_2_9_14_recovery_lt? ? %{<" hi} : %{ hi}
|
58
58
|
assert_equal(expected, full_sanitize(input))
|
59
59
|
end
|
60
60
|
|
@@ -77,19 +77,19 @@ class SanitizersTest < Minitest::Test
|
|
77
77
|
|
78
78
|
def test_remove_unclosed_tags
|
79
79
|
input = "This is <-- not\n a comment here."
|
80
|
-
expected =
|
80
|
+
expected = libxml_2_9_14_recovery_lt? ? %{This is <-- not\n a comment here.} : %{This is }
|
81
81
|
assert_equal(expected, full_sanitize(input))
|
82
82
|
end
|
83
83
|
|
84
84
|
def test_strip_cdata
|
85
85
|
input = "This has a <![CDATA[<section>]]> here."
|
86
|
-
expected =
|
86
|
+
expected = libxml_2_9_14_recovery_lt_bang? ? %{This has a <![CDATA[]]> here.} : %{This has a ]]> here.}
|
87
87
|
assert_equal(expected, full_sanitize(input))
|
88
88
|
end
|
89
89
|
|
90
90
|
def test_strip_unclosed_cdata
|
91
91
|
input = "This has an unclosed <![CDATA[<section>]] here..."
|
92
|
-
expected =
|
92
|
+
expected = libxml_2_9_14_recovery_lt_bang? ? %{This has an unclosed <![CDATA[]] here...} : %{This has an unclosed ]] here...}
|
93
93
|
assert_equal(expected, full_sanitize(input))
|
94
94
|
end
|
95
95
|
|
@@ -458,13 +458,13 @@ class SanitizersTest < Minitest::Test
|
|
458
458
|
|
459
459
|
def test_should_sanitize_cdata_section
|
460
460
|
input = "<![CDATA[<span>section</span>]]>"
|
461
|
-
expected =
|
461
|
+
expected = libxml_2_9_14_recovery_lt_bang? ? %{<![CDATA[<span>section</span>]]>} : %{section]]>}
|
462
462
|
assert_sanitized(input, expected)
|
463
463
|
end
|
464
464
|
|
465
465
|
def test_should_sanitize_unterminated_cdata_section
|
466
466
|
input = "<![CDATA[<span>neverending..."
|
467
|
-
expected =
|
467
|
+
expected = libxml_2_9_14_recovery_lt_bang? ? %{<![CDATA[<span>neverending...</span>} : %{neverending...}
|
468
468
|
assert_sanitized(input, expected)
|
469
469
|
end
|
470
470
|
|
@@ -581,23 +581,124 @@ class SanitizersTest < Minitest::Test
|
|
581
581
|
assert_equal("<div>text</div><b>text</b>", safe_list_sanitize("<div>text</div><!-- comment --><b>text</b>"))
|
582
582
|
end
|
583
583
|
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
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
590
|
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
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)
|
599
639
|
end
|
600
|
-
|
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)
|
601
702
|
end
|
602
703
|
|
603
704
|
protected
|
@@ -657,11 +758,14 @@ protected
|
|
657
758
|
end.join
|
658
759
|
end
|
659
760
|
|
660
|
-
def
|
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
|
661
763
|
Nokogiri.method(:uses_libxml?).arity == -1 && Nokogiri.uses_libxml?(">= 2.9.14")
|
662
764
|
end
|
663
765
|
|
664
|
-
def
|
665
|
-
|
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")
|
666
770
|
end
|
667
771
|
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.
|
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: 2022-
|
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
|
@@ -103,9 +109,9 @@ licenses:
|
|
103
109
|
- MIT
|
104
110
|
metadata:
|
105
111
|
bug_tracker_uri: https://github.com/rails/rails-html-sanitizer/issues
|
106
|
-
changelog_uri: https://github.com/rails/rails-html-sanitizer/blob/v1.4.
|
107
|
-
documentation_uri: https://www.rubydoc.info/gems/rails-html-sanitizer/1.4.
|
108
|
-
source_code_uri: https://github.com/rails/rails-html-sanitizer/tree/v1.4.
|
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
|
109
115
|
post_install_message:
|
110
116
|
rdoc_options: []
|
111
117
|
require_paths:
|
@@ -121,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
127
|
- !ruby/object:Gem::Version
|
122
128
|
version: '0'
|
123
129
|
requirements: []
|
124
|
-
rubygems_version: 3.3.
|
130
|
+
rubygems_version: 3.3.7
|
125
131
|
signing_key:
|
126
132
|
specification_version: 4
|
127
133
|
summary: This gem is responsible to sanitize HTML fragments in Rails applications.
|