rails-html-sanitizer 1.4.3 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +44 -1
- data/README.md +73 -0
- data/lib/rails/html/sanitizer/version.rb +1 -1
- data/lib/rails/html/sanitizer.rb +3 -20
- data/lib/rails/html/scrubbers.rb +12 -13
- data/test/sanitizer_test.rb +134 -24
- data/test/scrubbers_test.rb +14 -0
- 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: 59897b4a0d7f69a21932ec1cb44e24ea0ba4c2cf79ef7101ef32e90f40ad766b
|
4
|
+
data.tar.gz: '063919ea5426a6938040672fefeabcaf82087a5ccd12ffc7457e34eb6984042b'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b0c23a07bc8acb3c1a039266cf053ad9044670a96620365b3ed722eb9a602def1bebe8de40697a2b12deba61cf224461ae8a4dc93749fa8c9675cda4cd216dd
|
7
|
+
data.tar.gz: 5dce2af04dd887e08773a975cc67d93987b15330d023cc68a6cc51322ed73b60681309b25feab1a2c54b0e062696af1dd78c83cdb609e8d179b6ef95419573b3
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,47 @@
|
|
1
|
+
## 1.5.0 / 2023-01-20
|
2
|
+
|
3
|
+
* `SafeListSanitizer`, `PermitScrubber`, and `TargetScrubber` now all support pruning of unsafe tags.
|
4
|
+
|
5
|
+
By default, unsafe tags are still stripped, but this behavior can be changed to prune the element
|
6
|
+
and its children from the document by passing `prune: true` to any of these classes' constructors.
|
7
|
+
|
8
|
+
*seyerian*
|
9
|
+
|
10
|
+
## 1.4.4 / 2022-12-13
|
11
|
+
|
12
|
+
* Address inefficient regular expression complexity with certain configurations of Rails::Html::Sanitizer.
|
13
|
+
|
14
|
+
Fixes CVE-2022-23517. See
|
15
|
+
[GHSA-5x79-w82f-gw8w](https://github.com/rails/rails-html-sanitizer/security/advisories/GHSA-5x79-w82f-gw8w)
|
16
|
+
for more information.
|
17
|
+
|
18
|
+
*Mike Dalessio*
|
19
|
+
|
20
|
+
* Address improper sanitization of data URIs.
|
21
|
+
|
22
|
+
Fixes CVE-2022-23518 and #135. See
|
23
|
+
[GHSA-mcvf-2q2m-x72m](https://github.com/rails/rails-html-sanitizer/security/advisories/GHSA-mcvf-2q2m-x72m)
|
24
|
+
for more information.
|
25
|
+
|
26
|
+
*Mike Dalessio*
|
27
|
+
|
28
|
+
* Address possible XSS vulnerability with certain configurations of Rails::Html::Sanitizer.
|
29
|
+
|
30
|
+
Fixes CVE-2022-23520. See
|
31
|
+
[GHSA-rrfc-7g8p-99q8](https://github.com/rails/rails-html-sanitizer/security/advisories/GHSA-rrfc-7g8p-99q8)
|
32
|
+
for more information.
|
33
|
+
|
34
|
+
*Mike Dalessio*
|
35
|
+
|
36
|
+
* Address possible XSS vulnerability with certain configurations of Rails::Html::Sanitizer.
|
37
|
+
|
38
|
+
Fixes CVE-2022-23519. See
|
39
|
+
[GHSA-9h9g-93gc-623h](https://github.com/rails/rails-html-sanitizer/security/advisories/GHSA-9h9g-93gc-623h)
|
40
|
+
for more information.
|
41
|
+
|
42
|
+
*Mike Dalessio*
|
43
|
+
|
44
|
+
|
1
45
|
## 1.4.3 / 2022-06-09
|
2
46
|
|
3
47
|
* Address a possible XSS vulnerability with certain configurations of Rails::Html::Sanitizer.
|
@@ -8,7 +52,6 @@
|
|
8
52
|
|
9
53
|
*Mike Dalessio*
|
10
54
|
|
11
|
-
|
12
55
|
## 1.4.2 / 2021-08-23
|
13
56
|
|
14
57
|
* Slightly improve performance.
|
data/README.md
CHANGED
@@ -21,6 +21,35 @@ Or install it yourself as:
|
|
21
21
|
|
22
22
|
## Usage
|
23
23
|
|
24
|
+
### A note on HTML entities
|
25
|
+
|
26
|
+
__Rails::HTML sanitizers are intended to be used by the view layer, at page-render time. They are *not* intended to sanitize persisted strings that will sanitized *again* at page-render time.__
|
27
|
+
|
28
|
+
Proper HTML sanitization will replace some characters with HTML entities. For example, `<` will be replaced with `<` to ensure that the markup is well-formed.
|
29
|
+
|
30
|
+
This is important to keep in mind because __HTML entities will render improperly if they are sanitized twice.__
|
31
|
+
|
32
|
+
|
33
|
+
#### A concrete example showing the problem that can arise
|
34
|
+
|
35
|
+
Imagine the user is asked to enter their employer's name, which will appear on their public profile page. Then imagine they enter `JPMorgan Chase & Co.`.
|
36
|
+
|
37
|
+
If you sanitize this before persisting it in the database, the stored string will be `JPMorgan Chase & Co.`
|
38
|
+
|
39
|
+
When the page is rendered, if this string is sanitized a second time by the view layer, the HTML will contain `JPMorgan Chase &amp; Co.` which will render as "JPMorgan Chase &amp; Co.".
|
40
|
+
|
41
|
+
Another problem that can arise is rendering the sanitized string in a non-HTML context (for example, if it ends up being part of an SMS message). In this case, it may contain inappropriate HTML entities.
|
42
|
+
|
43
|
+
|
44
|
+
#### Suggested alternatives
|
45
|
+
|
46
|
+
You might simply choose to persist the untrusted string as-is (the raw input), and then ensure that the string will be properly sanitized by the view layer.
|
47
|
+
|
48
|
+
That raw string, if rendered in an non-HTML context (like SMS), must also be sanitized by a method appropriate for that context. You may wish to look into using [Loofah](https://github.com/flavorjones/loofah) or [Sanitize](https://github.com/rgrove/sanitize) to customize how this sanitization works, including omitting HTML entities in the final string.
|
49
|
+
|
50
|
+
If you really want to sanitize the string that's stored in your database, you may wish to look into [Loofah::ActiveRecord](https://github.com/flavorjones/loofah-activerecord) rather than use the Rails::HTML sanitizers.
|
51
|
+
|
52
|
+
|
24
53
|
### Sanitizers
|
25
54
|
|
26
55
|
All sanitizers respond to `sanitize`.
|
@@ -57,6 +86,9 @@ safe_list_sanitizer.sanitize(@article.body, scrubber: ArticleScrubber.new)
|
|
57
86
|
|
58
87
|
# safe list sanitizer can also sanitize css
|
59
88
|
safe_list_sanitizer.sanitize_css('background-color: #000;')
|
89
|
+
|
90
|
+
# fully prune nodes from the tree instead of stripping tags and leaving inner content
|
91
|
+
safe_list_sanitizer = Rails::Html::SafeListSanitizer.new(prune: true)
|
60
92
|
```
|
61
93
|
|
62
94
|
### Scrubbers
|
@@ -78,6 +110,24 @@ html_fragment.scrub!(scrubber)
|
|
78
110
|
html_fragment.to_s # => "<a></a>"
|
79
111
|
```
|
80
112
|
|
113
|
+
By default, inner content is left, but it can be removed as well.
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
scrubber = Rails::Html::PermitScrubber.new
|
117
|
+
scrubber.tags = ['a']
|
118
|
+
|
119
|
+
html_fragment = Loofah.fragment('<a><span>text</span></a>')
|
120
|
+
html_fragment.scrub!(scrubber)
|
121
|
+
html_fragment.to_s # => "<a>text</a>"
|
122
|
+
|
123
|
+
scrubber = Rails::Html::PermitScrubber.new(prune: true)
|
124
|
+
scrubber.tags = ['a']
|
125
|
+
|
126
|
+
html_fragment = Loofah.fragment('<a><span>text</span></a>')
|
127
|
+
html_fragment.scrub!(scrubber)
|
128
|
+
html_fragment.to_s # => "<a></a>"
|
129
|
+
```
|
130
|
+
|
81
131
|
#### `Rails::Html::TargetScrubber`
|
82
132
|
|
83
133
|
Where `PermitScrubber` picks out tags and attributes to permit in sanitization,
|
@@ -95,6 +145,23 @@ html_fragment.scrub!(scrubber)
|
|
95
145
|
html_fragment.to_s # => "<a></a>"
|
96
146
|
```
|
97
147
|
|
148
|
+
Similarly to `PermitScrubber`, nodes can be fully pruned.
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
scrubber = Rails::Html::TargetScrubber.new
|
152
|
+
scrubber.tags = ['span']
|
153
|
+
|
154
|
+
html_fragment = Loofah.fragment('<a><span>text</span></a>')
|
155
|
+
html_fragment.scrub!(scrubber)
|
156
|
+
html_fragment.to_s # => "<a>text</a>"
|
157
|
+
|
158
|
+
scrubber = Rails::Html::TargetScrubber.new(prune: true)
|
159
|
+
scrubber.tags = ['span']
|
160
|
+
|
161
|
+
html_fragment = Loofah.fragment('<a><span>text</span></a>')
|
162
|
+
html_fragment.scrub!(scrubber)
|
163
|
+
html_fragment.to_s # => "<a></a>"
|
164
|
+
```
|
98
165
|
#### Custom Scrubbers
|
99
166
|
|
100
167
|
You can also create custom scrubbers in your application if you want to.
|
@@ -138,5 +205,11 @@ Rails Html Sanitizers is work of many contributors. You're encouraged to submit
|
|
138
205
|
|
139
206
|
See [CONTRIBUTING](CONTRIBUTING.md).
|
140
207
|
|
208
|
+
### Security reports
|
209
|
+
|
210
|
+
Trying to report a possible security vulnerability in this project? Please
|
211
|
+
check out our [security policy](https://rubyonrails.org/security) for
|
212
|
+
guidelines about how to proceed.
|
213
|
+
|
141
214
|
## License
|
142
215
|
Rails Html Sanitizers is released under the [MIT License](MIT-LICENSE).
|
data/lib/rails/html/sanitizer.rb
CHANGED
@@ -110,8 +110,8 @@ module Rails
|
|
110
110
|
acronym a img blockquote del ins))
|
111
111
|
self.allowed_attributes = Set.new(%w(href src width height alt cite datetime title class name xml:lang abbr))
|
112
112
|
|
113
|
-
def initialize
|
114
|
-
@permit_scrubber = PermitScrubber.new
|
113
|
+
def initialize(prune: false)
|
114
|
+
@permit_scrubber = PermitScrubber.new(prune: prune)
|
115
115
|
end
|
116
116
|
|
117
117
|
def sanitize(html, options = {})
|
@@ -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
@@ -45,10 +45,11 @@ module Rails
|
|
45
45
|
# See the documentation for +Nokogiri::XML::Node+ to understand what's possible
|
46
46
|
# with nodes: https://nokogiri.org/rdoc/Nokogiri/XML/Node.html
|
47
47
|
class PermitScrubber < Loofah::Scrubber
|
48
|
-
attr_reader :tags, :attributes
|
48
|
+
attr_reader :tags, :attributes, :prune
|
49
49
|
|
50
|
-
def initialize
|
51
|
-
@
|
50
|
+
def initialize(prune: false)
|
51
|
+
@prune = prune
|
52
|
+
@direction = @prune ? :top_down : :bottom_up
|
52
53
|
@tags, @attributes = nil, nil
|
53
54
|
end
|
54
55
|
|
@@ -61,9 +62,9 @@ module Rails
|
|
61
62
|
end
|
62
63
|
|
63
64
|
def scrub(node)
|
64
|
-
if
|
65
|
-
|
66
|
-
node.replace
|
65
|
+
if Loofah::HTML5::Scrub.cdata_needs_escaping?(node)
|
66
|
+
replacement = Loofah::HTML5::Scrub.cdata_escape(node)
|
67
|
+
node.replace(replacement)
|
67
68
|
return CONTINUE
|
68
69
|
end
|
69
70
|
return CONTINUE if skip_node?(node)
|
@@ -98,7 +99,7 @@ module Rails
|
|
98
99
|
end
|
99
100
|
|
100
101
|
def scrub_node(node)
|
101
|
-
node.before(node.children) # strip
|
102
|
+
node.before(node.children) unless prune # strip
|
102
103
|
node.remove
|
103
104
|
end
|
104
105
|
|
@@ -139,15 +140,13 @@ module Rails
|
|
139
140
|
end
|
140
141
|
|
141
142
|
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
|
143
|
+
return if Loofah::HTML5::Scrub.scrub_uri_attribute(attr_node)
|
147
144
|
end
|
145
|
+
|
148
146
|
if Loofah::HTML5::SafeList::SVG_ATTR_VAL_ALLOWS_REF.include?(attr_name)
|
149
|
-
|
147
|
+
Loofah::HTML5::Scrub.scrub_attribute_that_allows_local_ref(attr_node)
|
150
148
|
end
|
149
|
+
|
151
150
|
if Loofah::HTML5::SafeList::SVG_ALLOW_LOCAL_HREF.include?(node.name) && attr_name == 'xlink:href' && attr_node.value =~ /^\s*[^#\s].*/m
|
152
151
|
attr_node.remove
|
153
152
|
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
|
|
@@ -256,6 +256,12 @@ class SanitizersTest < Minitest::Test
|
|
256
256
|
end
|
257
257
|
end
|
258
258
|
|
259
|
+
def test_should_allow_prune
|
260
|
+
sanitizer = Rails::Html::SafeListSanitizer.new(prune: true)
|
261
|
+
text = '<u>leave me <b>now</b></u>'
|
262
|
+
assert_equal "<u>leave me </u>", sanitizer.sanitize(text, tags: %w(u))
|
263
|
+
end
|
264
|
+
|
259
265
|
def test_should_allow_custom_tags
|
260
266
|
text = "<u>foo</u>"
|
261
267
|
assert_equal text, safe_list_sanitize(text, tags: %w(u))
|
@@ -458,13 +464,13 @@ class SanitizersTest < Minitest::Test
|
|
458
464
|
|
459
465
|
def test_should_sanitize_cdata_section
|
460
466
|
input = "<![CDATA[<span>section</span>]]>"
|
461
|
-
expected =
|
467
|
+
expected = libxml_2_9_14_recovery_lt_bang? ? %{<![CDATA[<span>section</span>]]>} : %{section]]>}
|
462
468
|
assert_sanitized(input, expected)
|
463
469
|
end
|
464
470
|
|
465
471
|
def test_should_sanitize_unterminated_cdata_section
|
466
472
|
input = "<![CDATA[<span>neverending..."
|
467
|
-
expected =
|
473
|
+
expected = libxml_2_9_14_recovery_lt_bang? ? %{<![CDATA[<span>neverending...</span>} : %{neverending...}
|
468
474
|
assert_sanitized(input, expected)
|
469
475
|
end
|
470
476
|
|
@@ -581,23 +587,124 @@ class SanitizersTest < Minitest::Test
|
|
581
587
|
assert_equal("<div>text</div><b>text</b>", safe_list_sanitize("<div>text</div><!-- comment --><b>text</b>"))
|
582
588
|
end
|
583
589
|
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
+
%w[text/plain text/css image/png image/gif image/jpeg].each do |mediatype|
|
591
|
+
define_method "test_mediatype_#{mediatype}_allowed" do
|
592
|
+
input = %Q(<img src="data:#{mediatype};base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">)
|
593
|
+
expected = input
|
594
|
+
actual = safe_list_sanitize(input)
|
595
|
+
assert_equal(expected, actual)
|
590
596
|
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
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)
|
597
|
+
input = %Q(<img src="DATA:#{mediatype};base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">)
|
598
|
+
expected = input
|
599
|
+
actual = safe_list_sanitize(input)
|
600
|
+
assert_equal(expected, actual)
|
599
601
|
end
|
600
|
-
|
602
|
+
end
|
603
|
+
|
604
|
+
def test_mediatype_text_html_disallowed
|
605
|
+
input = %q(<img src="data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">)
|
606
|
+
expected = %q(<img>)
|
607
|
+
actual = safe_list_sanitize(input)
|
608
|
+
assert_equal(expected, actual)
|
609
|
+
|
610
|
+
input = %q(<img src="DATA:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">)
|
611
|
+
expected = %q(<img>)
|
612
|
+
actual = safe_list_sanitize(input)
|
613
|
+
assert_equal(expected, actual)
|
614
|
+
end
|
615
|
+
|
616
|
+
def test_mediatype_image_svg_xml_disallowed
|
617
|
+
input = %q(<img src="data:image/svg+xml;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">)
|
618
|
+
expected = %q(<img>)
|
619
|
+
actual = safe_list_sanitize(input)
|
620
|
+
assert_equal(expected, actual)
|
621
|
+
|
622
|
+
input = %q(<img src="DATA:image/svg+xml;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">)
|
623
|
+
expected = %q(<img>)
|
624
|
+
actual = safe_list_sanitize(input)
|
625
|
+
assert_equal(expected, actual)
|
626
|
+
end
|
627
|
+
|
628
|
+
def test_mediatype_other_disallowed
|
629
|
+
input = %q(<a href="data:foo;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">foo</a>)
|
630
|
+
expected = %q(<a>foo</a>)
|
631
|
+
actual = safe_list_sanitize(input)
|
632
|
+
assert_equal(expected, actual)
|
633
|
+
|
634
|
+
input = %q(<a href="DATA:foo;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">foo</a>)
|
635
|
+
expected = %q(<a>foo</a>)
|
636
|
+
actual = safe_list_sanitize(input)
|
637
|
+
assert_equal(expected, actual)
|
638
|
+
end
|
639
|
+
|
640
|
+
def test_scrubbing_svg_attr_values_that_allow_ref
|
641
|
+
input = %Q(<div fill="yellow url(http://bad.com/) #fff">hey</div>)
|
642
|
+
expected = %Q(<div fill="yellow #fff">hey</div>)
|
643
|
+
actual = scope_allowed_attributes %w(fill) do
|
644
|
+
safe_list_sanitize(input)
|
645
|
+
end
|
646
|
+
|
647
|
+
assert_equal(expected, actual)
|
648
|
+
end
|
649
|
+
|
650
|
+
def test_style_with_css_payload
|
651
|
+
input, tags = "<style>div > span { background: \"red\"; }</style>", ["style"]
|
652
|
+
expected = "<style>div > span { background: \"red\"; }</style>"
|
653
|
+
actual = safe_list_sanitize(input, tags: tags)
|
654
|
+
|
655
|
+
assert_equal(expected, actual)
|
656
|
+
end
|
657
|
+
|
658
|
+
def test_combination_of_select_and_style_with_css_payload
|
659
|
+
input, tags = "<select><style>div > span { background: \"red\"; }</style></select>", ["select", "style"]
|
660
|
+
expected = "<select><style>div > span { background: \"red\"; }</style></select>"
|
661
|
+
actual = safe_list_sanitize(input, tags: tags)
|
662
|
+
|
663
|
+
assert_equal(expected, actual)
|
664
|
+
end
|
665
|
+
|
666
|
+
def test_combination_of_select_and_style_with_script_payload
|
667
|
+
input, tags = "<select><style><script>alert(1)</script></style></select>", ["select", "style"]
|
668
|
+
expected = "<select><style><script>alert(1)</script></style></select>"
|
669
|
+
actual = safe_list_sanitize(input, tags: tags)
|
670
|
+
|
671
|
+
assert_equal(expected, actual)
|
672
|
+
end
|
673
|
+
|
674
|
+
def test_combination_of_svg_and_style_with_script_payload
|
675
|
+
input, tags = "<svg><style><script>alert(1)</script></style></svg>", ["svg", "style"]
|
676
|
+
expected = "<svg><style><script>alert(1)</script></style></svg>"
|
677
|
+
actual = safe_list_sanitize(input, tags: tags)
|
678
|
+
|
679
|
+
assert_equal(expected, actual)
|
680
|
+
end
|
681
|
+
|
682
|
+
def test_combination_of_math_and_style_with_img_payload
|
683
|
+
input, tags = "<math><style><img src=x onerror=alert(1)></style></math>", ["math", "style"]
|
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
|
+
|
689
|
+
input, tags = "<math><style><img src=x onerror=alert(1)></style></math>", ["math", "style", "img"]
|
690
|
+
expected = "<math><style><img src=x onerror=alert(1)></style></math>"
|
691
|
+
actual = safe_list_sanitize(input, tags: tags)
|
692
|
+
|
693
|
+
assert_equal(expected, actual)
|
694
|
+
end
|
695
|
+
|
696
|
+
def test_combination_of_svg_and_style_with_img_payload
|
697
|
+
input, tags = "<svg><style><img src=x onerror=alert(1)></style></svg>", ["svg", "style"]
|
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)
|
702
|
+
|
703
|
+
input, tags = "<svg><style><img src=x onerror=alert(1)></style></svg>", ["svg", "style", "img"]
|
704
|
+
expected = "<svg><style><img src=x onerror=alert(1)></style></svg>"
|
705
|
+
actual = safe_list_sanitize(input, tags: tags)
|
706
|
+
|
707
|
+
assert_equal(expected, actual)
|
601
708
|
end
|
602
709
|
|
603
710
|
protected
|
@@ -657,11 +764,14 @@ protected
|
|
657
764
|
end.join
|
658
765
|
end
|
659
766
|
|
660
|
-
def
|
767
|
+
def libxml_2_9_14_recovery_lt?
|
768
|
+
# changed in 2.9.14, see https://github.com/sparklemotion/nokogiri/releases/tag/v1.13.5
|
661
769
|
Nokogiri.method(:uses_libxml?).arity == -1 && Nokogiri.uses_libxml?(">= 2.9.14")
|
662
770
|
end
|
663
771
|
|
664
|
-
def
|
665
|
-
|
772
|
+
def libxml_2_9_14_recovery_lt_bang?
|
773
|
+
# changed in 2.9.14, see https://github.com/sparklemotion/nokogiri/releases/tag/v1.13.5
|
774
|
+
# then reverted in 2.10.0, see https://gitlab.gnome.org/GNOME/libxml2/-/issues/380
|
775
|
+
Nokogiri.method(:uses_libxml?).arity == -1 && Nokogiri.uses_libxml?("= 2.9.14")
|
666
776
|
end
|
667
777
|
end
|
data/test/scrubbers_test.rb
CHANGED
@@ -66,6 +66,13 @@ class PermitScrubberTest < ScrubberTest
|
|
66
66
|
assert_scrubbed html, '<tag>leave me now</tag>'
|
67
67
|
end
|
68
68
|
|
69
|
+
def test_prunes_tags
|
70
|
+
@scrubber = Rails::Html::PermitScrubber.new(prune: true)
|
71
|
+
@scrubber.tags = %w(tag)
|
72
|
+
html = '<tag>leave me <span>now</span></tag>'
|
73
|
+
assert_scrubbed html, '<tag>leave me </tag>'
|
74
|
+
end
|
75
|
+
|
69
76
|
def test_leaves_comments_when_supplied_as_tag
|
70
77
|
@scrubber.tags = %w(div comment)
|
71
78
|
assert_scrubbed('<div>one</div><!-- two --><span>three</span>',
|
@@ -157,6 +164,13 @@ class TargetScrubberTest < ScrubberTest
|
|
157
164
|
html = '<tag remove="" other=""></tag><a remove="" other=""></a>'
|
158
165
|
assert_scrubbed html, '<a other=""></a>'
|
159
166
|
end
|
167
|
+
|
168
|
+
def test_prunes_tags
|
169
|
+
@scrubber = Rails::Html::TargetScrubber.new(prune: true)
|
170
|
+
@scrubber.tags = %w(span)
|
171
|
+
html = '<tag>leave me <span>now</span></tag>'
|
172
|
+
assert_scrubbed html, '<tag>leave me </tag>'
|
173
|
+
end
|
160
174
|
end
|
161
175
|
|
162
176
|
class TextOnlyScrubberTest < ScrubberTest
|
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.5.0
|
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: 2023-01-20 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.
|
107
|
-
documentation_uri: https://www.rubydoc.info/gems/rails-html-sanitizer/1.
|
108
|
-
source_code_uri: https://github.com/rails/rails-html-sanitizer/tree/v1.
|
112
|
+
changelog_uri: https://github.com/rails/rails-html-sanitizer/blob/v1.5.0/CHANGELOG.md
|
113
|
+
documentation_uri: https://www.rubydoc.info/gems/rails-html-sanitizer/1.5.0
|
114
|
+
source_code_uri: https://github.com/rails/rails-html-sanitizer/tree/v1.5.0
|
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.
|
130
|
+
rubygems_version: 3.4.2
|
125
131
|
signing_key:
|
126
132
|
specification_version: 4
|
127
133
|
summary: This gem is responsible to sanitize HTML fragments in Rails applications.
|