rails-html-sanitizer 1.4.3 → 1.5.0
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 +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.
|