loofah 2.2.3 → 2.3.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of loofah might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +37 -0
- data/Gemfile +3 -3
- data/Manifest.txt +2 -1
- data/README.md +6 -13
- data/Rakefile +22 -20
- data/lib/loofah.rb +15 -15
- data/lib/loofah/helpers.rb +13 -3
- data/lib/loofah/html5/safelist.rb +796 -0
- data/lib/loofah/html5/scrub.rb +14 -14
- data/lib/loofah/scrubbers.rb +1 -1
- data/test/html5/test_sanitizer.rb +36 -17
- data/test/html5/test_scrub.rb +10 -0
- data/test/integration/test_ad_hoc.rb +41 -25
- data/test/unit/test_helpers.rb +4 -4
- metadata +37 -43
- data/lib/loofah/html5/whitelist.rb +0 -186
data/lib/loofah/html5/scrub.rb
CHANGED
@@ -6,13 +6,13 @@ module Loofah
|
|
6
6
|
module Scrub
|
7
7
|
|
8
8
|
CONTROL_CHARACTERS = /[`\u0000-\u0020\u007f\u0080-\u0101]/
|
9
|
-
CSS_KEYWORDISH = /\A(#[0-9a-
|
9
|
+
CSS_KEYWORDISH = /\A(#[0-9a-fA-F]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|-?\d{0,3}\.?\d{0,10}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)\z/
|
10
10
|
CRASS_SEMICOLON = {:node => :semicolon, :raw => ";"}
|
11
11
|
|
12
12
|
class << self
|
13
13
|
|
14
14
|
def allowed_element? element_name
|
15
|
-
::Loofah::HTML5::
|
15
|
+
::Loofah::HTML5::SafeList::ALLOWED_ELEMENTS_WITH_LIBXML2.include? element_name
|
16
16
|
end
|
17
17
|
|
18
18
|
# alternative implementation of the html5lib attribute scrubbing algorithm
|
@@ -28,31 +28,31 @@ module Loofah
|
|
28
28
|
next
|
29
29
|
end
|
30
30
|
|
31
|
-
unless
|
31
|
+
unless SafeList::ALLOWED_ATTRIBUTES.include?(attr_name)
|
32
32
|
attr_node.remove
|
33
33
|
next
|
34
34
|
end
|
35
35
|
|
36
|
-
if
|
36
|
+
if SafeList::ATTR_VAL_IS_URI.include?(attr_name)
|
37
37
|
# this block lifted nearly verbatim from HTML5 sanitization
|
38
38
|
val_unescaped = CGI.unescapeHTML(attr_node.value).gsub(CONTROL_CHARACTERS,'').downcase
|
39
|
-
if val_unescaped =~ /^[a-z0-9][-+.a-z0-9]*:/ && !
|
39
|
+
if val_unescaped =~ /^[a-z0-9][-+.a-z0-9]*:/ && ! SafeList::ALLOWED_PROTOCOLS.include?(val_unescaped.split(SafeList::PROTOCOL_SEPARATOR)[0])
|
40
40
|
attr_node.remove
|
41
41
|
next
|
42
|
-
elsif val_unescaped.split(
|
42
|
+
elsif val_unescaped.split(SafeList::PROTOCOL_SEPARATOR)[0] == 'data'
|
43
43
|
# permit only allowed data mediatypes
|
44
|
-
mediatype = val_unescaped.split(
|
44
|
+
mediatype = val_unescaped.split(SafeList::PROTOCOL_SEPARATOR)[1]
|
45
45
|
mediatype, _ = mediatype.split(';')[0..1] if mediatype
|
46
|
-
if mediatype && !
|
46
|
+
if mediatype && !SafeList::ALLOWED_URI_DATA_MEDIATYPES.include?(mediatype)
|
47
47
|
attr_node.remove
|
48
48
|
next
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
52
|
-
if
|
52
|
+
if SafeList::SVG_ATTR_VAL_ALLOWS_REF.include?(attr_name)
|
53
53
|
attr_node.value = attr_node.value.gsub(/url\s*\(\s*[^#\s][^)]+?\)/m, ' ') if attr_node.value
|
54
54
|
end
|
55
|
-
if
|
55
|
+
if SafeList::SVG_ALLOW_LOCAL_HREF.include?(node.name) && attr_name == 'xlink:href' && attr_node.value =~ /^\s*[^#\s].*/m
|
56
56
|
attr_node.remove
|
57
57
|
next
|
58
58
|
end
|
@@ -79,14 +79,14 @@ module Loofah
|
|
79
79
|
style_tree.each do |node|
|
80
80
|
next unless node[:node] == :property
|
81
81
|
next if node[:children].any? do |child|
|
82
|
-
[:url, :bad_url].include?(child[:node]) || (child[:node] == :function && !
|
82
|
+
[:url, :bad_url].include?(child[:node]) || (child[:node] == :function && !SafeList::ALLOWED_CSS_FUNCTIONS.include?(child[:name].downcase))
|
83
83
|
end
|
84
84
|
name = node[:name].downcase
|
85
|
-
if
|
85
|
+
if SafeList::ALLOWED_CSS_PROPERTIES.include?(name) || SafeList::ALLOWED_SVG_PROPERTIES.include?(name)
|
86
86
|
sanitized_tree << node << CRASS_SEMICOLON
|
87
|
-
elsif
|
87
|
+
elsif SafeList::SHORTHAND_CSS_PROPERTIES.include?(name.split('-').first)
|
88
88
|
value = node[:value].split.map do |keyword|
|
89
|
-
if
|
89
|
+
if SafeList::ALLOWED_CSS_KEYWORDS.include?(keyword) || keyword =~ CSS_KEYWORDISH
|
90
90
|
keyword
|
91
91
|
end
|
92
92
|
end.compact
|
data/lib/loofah/scrubbers.rb
CHANGED
@@ -37,7 +37,7 @@ class Html5TestSanitizer < Loofah::TestCase
|
|
37
37
|
assert_in_delta t0, Time.now, 0.1 # arbitrary seconds
|
38
38
|
end
|
39
39
|
|
40
|
-
(HTML5::
|
40
|
+
(HTML5::SafeList::ALLOWED_ELEMENTS).each do |tag_name|
|
41
41
|
define_method "test_should_allow_#{tag_name}_tag" do
|
42
42
|
input = "<#{tag_name} title='1'>foo <bad>bar</bad> baz</#{tag_name}>"
|
43
43
|
htmloutput = "<#{tag_name.downcase} title='1'>foo <bad>bar</bad> baz</#{tag_name.downcase}>"
|
@@ -58,7 +58,7 @@ class Html5TestSanitizer < Loofah::TestCase
|
|
58
58
|
htmloutput = "<img title='1'/>foo <bad>bar</bad> baz"
|
59
59
|
xhtmloutput = htmloutput
|
60
60
|
rexmloutput = "<image title='1'>foo <bad>bar</bad> baz</image>"
|
61
|
-
elsif HTML5::
|
61
|
+
elsif HTML5::SafeList::VOID_ELEMENTS.include?(tag_name)
|
62
62
|
htmloutput = "<#{tag_name} title='1'>foo <bad>bar</bad> baz"
|
63
63
|
xhtmloutput = htmloutput
|
64
64
|
htmloutput += '<br/>' if tag_name == 'br'
|
@@ -71,7 +71,7 @@ class Html5TestSanitizer < Loofah::TestCase
|
|
71
71
|
##
|
72
72
|
## libxml2 downcases elements, so this is moot.
|
73
73
|
##
|
74
|
-
# HTML5::
|
74
|
+
# HTML5::SafeList::ALLOWED_ELEMENTS.each do |tag_name|
|
75
75
|
# define_method "test_should_forbid_#{tag_name.upcase}_tag" do
|
76
76
|
# input = "<#{tag_name.upcase} title='1'>foo <bad>bar</bad> baz</#{tag_name.upcase}>"
|
77
77
|
# output = "<#{tag_name.upcase} title=\"1\">foo <bad>bar</bad> baz</#{tag_name.upcase}>"
|
@@ -79,7 +79,7 @@ class Html5TestSanitizer < Loofah::TestCase
|
|
79
79
|
# end
|
80
80
|
# end
|
81
81
|
|
82
|
-
HTML5::
|
82
|
+
HTML5::SafeList::ALLOWED_ATTRIBUTES.each do |attribute_name|
|
83
83
|
next if attribute_name == 'style'
|
84
84
|
define_method "test_should_allow_#{attribute_name}_attribute" do
|
85
85
|
input = "<p #{attribute_name}='foo'>foo <bad>bar</bad> baz</p>"
|
@@ -110,10 +110,17 @@ class Html5TestSanitizer < Loofah::TestCase
|
|
110
110
|
check_sanitization(input, htmloutput, output, output)
|
111
111
|
end
|
112
112
|
|
113
|
+
def test_should_allow_contenteditable
|
114
|
+
input = '<p contenteditable="false">Hi!</p>'
|
115
|
+
output = '<p contenteditable="false">Hi!</p>'
|
116
|
+
|
117
|
+
check_sanitization(input, output, output, output)
|
118
|
+
end
|
119
|
+
|
113
120
|
##
|
114
121
|
## libxml2 downcases attributes, so this is moot.
|
115
122
|
##
|
116
|
-
# HTML5::
|
123
|
+
# HTML5::SafeList::ALLOWED_ATTRIBUTES.each do |attribute_name|
|
117
124
|
# define_method "test_should_forbid_#{attribute_name.upcase}_attribute" do
|
118
125
|
# input = "<p #{attribute_name.upcase}='display: none;'>foo <bad>bar</bad> baz</p>"
|
119
126
|
# output = "<p>foo <bad>bar</bad> baz</p>"
|
@@ -121,7 +128,7 @@ class Html5TestSanitizer < Loofah::TestCase
|
|
121
128
|
# end
|
122
129
|
# end
|
123
130
|
|
124
|
-
HTML5::
|
131
|
+
HTML5::SafeList::ALLOWED_PROTOCOLS.each do |protocol|
|
125
132
|
define_method "test_should_allow_#{protocol}_uris" do
|
126
133
|
input = %(<a href="#{protocol}">foo</a>)
|
127
134
|
output = "<a href='#{protocol}'>foo</a>"
|
@@ -129,7 +136,7 @@ class Html5TestSanitizer < Loofah::TestCase
|
|
129
136
|
end
|
130
137
|
end
|
131
138
|
|
132
|
-
HTML5::
|
139
|
+
HTML5::SafeList::ALLOWED_PROTOCOLS.each do |protocol|
|
133
140
|
define_method "test_should_allow_uppercase_#{protocol}_uris" do
|
134
141
|
input = %(<a href="#{protocol.upcase}">foo</a>)
|
135
142
|
output = "<a href='#{protocol.upcase}'>foo</a>"
|
@@ -137,7 +144,7 @@ class Html5TestSanitizer < Loofah::TestCase
|
|
137
144
|
end
|
138
145
|
end
|
139
146
|
|
140
|
-
HTML5::
|
147
|
+
HTML5::SafeList::ALLOWED_URI_DATA_MEDIATYPES.each do |data_uri_type|
|
141
148
|
define_method "test_should_allow_data_#{data_uri_type}_uris" do
|
142
149
|
input = %(<a href="data:#{data_uri_type}">foo</a>)
|
143
150
|
output = "<a href='data:#{data_uri_type}'>foo</a>"
|
@@ -149,7 +156,7 @@ class Html5TestSanitizer < Loofah::TestCase
|
|
149
156
|
end
|
150
157
|
end
|
151
158
|
|
152
|
-
HTML5::
|
159
|
+
HTML5::SafeList::ALLOWED_URI_DATA_MEDIATYPES.each do |data_uri_type|
|
153
160
|
define_method "test_should_allow_uppercase_data_#{data_uri_type}_uris" do
|
154
161
|
input = %(<a href="DATA:#{data_uri_type.upcase}">foo</a>)
|
155
162
|
output = "<a href='DATA:#{data_uri_type.upcase}'>foo</a>"
|
@@ -172,8 +179,8 @@ class Html5TestSanitizer < Loofah::TestCase
|
|
172
179
|
end
|
173
180
|
|
174
181
|
|
175
|
-
HTML5::
|
176
|
-
next unless HTML5::
|
182
|
+
HTML5::SafeList::SVG_ALLOW_LOCAL_HREF.each do |tag_name|
|
183
|
+
next unless HTML5::SafeList::ALLOWED_ELEMENTS.include?(tag_name)
|
177
184
|
define_method "test_#{tag_name}_should_allow_local_href" do
|
178
185
|
input = %(<#{tag_name} xlink:href="#foo"/>)
|
179
186
|
output = "<#{tag_name.downcase} xlink:href='#foo'></#{tag_name.downcase}>"
|
@@ -249,7 +256,7 @@ class Html5TestSanitizer < Loofah::TestCase
|
|
249
256
|
end
|
250
257
|
|
251
258
|
## added because we don't have any coverage above on SVG_ATTR_VAL_ALLOWS_REF
|
252
|
-
HTML5::
|
259
|
+
HTML5::SafeList::SVG_ATTR_VAL_ALLOWS_REF.each do |attr_name|
|
253
260
|
define_method "test_should_allow_uri_refs_in_svg_attribute_#{attr_name}" do
|
254
261
|
input = "<rect fill='url(#foo)' />"
|
255
262
|
output = "<rect fill='url(#foo)'></rect>"
|
@@ -263,6 +270,12 @@ class Html5TestSanitizer < Loofah::TestCase
|
|
263
270
|
end
|
264
271
|
end
|
265
272
|
|
273
|
+
def test_css_list_style
|
274
|
+
html = '<ul style="list-style: none"></ul>'
|
275
|
+
sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :escape).to_xml)
|
276
|
+
assert_match %r/list-style/, sane.inner_html
|
277
|
+
end
|
278
|
+
|
266
279
|
def test_css_negative_value_sanitization
|
267
280
|
html = "<span style=\"letter-spacing:-0.03em;\">"
|
268
281
|
sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :escape).to_xml)
|
@@ -275,7 +288,13 @@ class Html5TestSanitizer < Loofah::TestCase
|
|
275
288
|
assert_match %r/-0.05em/, sane.inner_html
|
276
289
|
end
|
277
290
|
|
278
|
-
def
|
291
|
+
def test_css_high_precision_value_shorthand_css_properties
|
292
|
+
html = "<span style=\"margin-left:0.3333333334em;\">"
|
293
|
+
sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :escape).to_xml)
|
294
|
+
assert_match %r/0.3333333334em/, sane.inner_html
|
295
|
+
end
|
296
|
+
|
297
|
+
def test_css_function_sanitization_leaves_safelisted_functions_calc
|
279
298
|
html = "<span style=\"width:calc(5%)\">"
|
280
299
|
sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :strip).to_html)
|
281
300
|
assert_match %r/calc\(5%\)/, sane.inner_html
|
@@ -285,24 +304,24 @@ class Html5TestSanitizer < Loofah::TestCase
|
|
285
304
|
assert_match %r/calc\(5%\)/, sane.inner_html
|
286
305
|
end
|
287
306
|
|
288
|
-
def
|
307
|
+
def test_css_function_sanitization_leaves_safelisted_functions_rgb
|
289
308
|
html = '<span style="color: rgb(255, 0, 0)">'
|
290
309
|
sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :strip).to_html)
|
291
310
|
assert_match %r/rgb\(255, 0, 0\)/, sane.inner_html
|
292
311
|
end
|
293
312
|
|
294
|
-
def
|
313
|
+
def test_css_function_sanitization_leaves_safelisted_list_style_type
|
295
314
|
html = "<ol style='list-style-type:lower-greek;'></ol>"
|
296
315
|
sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :strip).to_html)
|
297
316
|
assert_match %r/list-style-type:lower-greek/, sane.inner_html
|
298
317
|
end
|
299
318
|
|
300
319
|
def test_css_function_sanitization_strips_style_attributes_with_unsafe_functions
|
301
|
-
html = "<span style=\"width:
|
320
|
+
html = "<span style=\"width:url(data-evil-url)\">"
|
302
321
|
sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :strip).to_html)
|
303
322
|
assert_match %r/<span><\/span>/, sane.inner_html
|
304
323
|
|
305
|
-
html = "<span style=\"width:
|
324
|
+
html = "<span style=\"width: url(data-evil-url)\">"
|
306
325
|
sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :strip).to_html)
|
307
326
|
assert_match %r/<span><\/span>/, sane.inner_html
|
308
327
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class UnitHTML5Scrub < Loofah::TestCase
|
4
|
+
include Loofah
|
5
|
+
|
6
|
+
def test_scrub_css
|
7
|
+
assert_equal Loofah::HTML5::Scrub.scrub_css("background: #ABC012"), "background:#ABC012;"
|
8
|
+
assert_equal Loofah::HTML5::Scrub.scrub_css("background: #abc012"), "background:#abc012;"
|
9
|
+
end
|
10
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require "helper"
|
2
2
|
|
3
3
|
class IntegrationTestAdHoc < Loofah::TestCase
|
4
|
-
|
5
4
|
context "blank input string" do
|
6
5
|
context "fragment" do
|
7
6
|
it "return a blank string" do
|
@@ -33,9 +32,9 @@ class IntegrationTestAdHoc < Loofah::TestCase
|
|
33
32
|
html = "<p class=bar foo=bar abbr=bar />"
|
34
33
|
sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :escape).to_xml)
|
35
34
|
node = sane.xpath("//p").first
|
36
|
-
assert node.attributes[
|
37
|
-
assert node.attributes[
|
38
|
-
assert_nil node.attributes[
|
35
|
+
assert node.attributes["class"]
|
36
|
+
assert node.attributes["abbr"]
|
37
|
+
assert_nil node.attributes["foo"]
|
39
38
|
end
|
40
39
|
|
41
40
|
def test_removal_of_illegal_url_in_href
|
@@ -45,14 +44,14 @@ class IntegrationTestAdHoc < Loofah::TestCase
|
|
45
44
|
HTML
|
46
45
|
sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :escape).to_xml)
|
47
46
|
nodes = sane.xpath("//a")
|
48
|
-
assert_nil nodes.first.attributes[
|
49
|
-
assert nodes.last.attributes[
|
47
|
+
assert_nil nodes.first.attributes["href"]
|
48
|
+
assert nodes.last.attributes["href"]
|
50
49
|
end
|
51
50
|
|
52
51
|
def test_css_sanitization
|
53
52
|
html = "<p style='background-color: url(\"http://foo.com/\") ; background-color: #000 ;' />"
|
54
53
|
sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :escape).to_xml)
|
55
|
-
assert_match %r/#000/,
|
54
|
+
assert_match %r/#000/, sane.inner_html
|
56
55
|
refute_match %r/foo\.com/, sane.inner_html
|
57
56
|
end
|
58
57
|
|
@@ -75,7 +74,7 @@ class IntegrationTestAdHoc < Loofah::TestCase
|
|
75
74
|
def test_whitewash_on_fragment
|
76
75
|
html = "safe<frameset rows=\"*\"><frame src=\"http://example.com\"></frameset> <b>description</b>"
|
77
76
|
whitewashed = Loofah.scrub_document(html, :whitewash).xpath("/html/body/*").to_s
|
78
|
-
assert_equal "<p>safe</p><b>description</b>", whitewashed.gsub("\n","")
|
77
|
+
assert_equal "<p>safe</p><b>description</b>", whitewashed.gsub("\n", "")
|
79
78
|
end
|
80
79
|
|
81
80
|
def test_fragment_whitewash_on_microsofty_markup
|
@@ -86,11 +85,11 @@ class IntegrationTestAdHoc < Loofah::TestCase
|
|
86
85
|
def test_document_whitewash_on_microsofty_markup
|
87
86
|
whitewashed = Loofah.document(MSWORD_HTML).scrub!(:whitewash)
|
88
87
|
assert_match %r(<p>Foo <b>BOLD</b></p>), whitewashed.to_s
|
89
|
-
assert_equal "<p>Foo <b>BOLD</b></p>",
|
88
|
+
assert_equal "<p>Foo <b>BOLD</b></p>", whitewashed.xpath("/html/body/*").to_s
|
90
89
|
end
|
91
90
|
|
92
91
|
def test_return_empty_string_when_nothing_left
|
93
|
-
assert_equal "", Loofah.scrub_document(
|
92
|
+
assert_equal "", Loofah.scrub_document("<script>test</script>", :prune).text
|
94
93
|
end
|
95
94
|
|
96
95
|
def test_nested_script_cdata_tags_should_be_scrubbed
|
@@ -145,21 +144,20 @@ class IntegrationTestAdHoc < Loofah::TestCase
|
|
145
144
|
#
|
146
145
|
# https://git.gnome.org/browse/libxml2/tree/HTMLtree.c?h=v2.9.2#n714
|
147
146
|
#
|
148
|
-
{tag: "a",
|
149
|
-
{tag: "div", attr: "href"},
|
150
|
-
{tag: "a",
|
151
|
-
{tag: "div", attr: "action"},
|
152
|
-
{tag: "a",
|
153
|
-
{tag: "div", attr: "src"},
|
154
|
-
{tag: "a",
|
147
|
+
{ tag: "a", attr: "href" },
|
148
|
+
{ tag: "div", attr: "href" },
|
149
|
+
{ tag: "a", attr: "action" },
|
150
|
+
{ tag: "div", attr: "action" },
|
151
|
+
{ tag: "a", attr: "src" },
|
152
|
+
{ tag: "div", attr: "src" },
|
153
|
+
{ tag: "a", attr: "name" },
|
155
154
|
#
|
156
155
|
# note that div+name is _not_ affected by the libxml2 issue.
|
157
156
|
# but we test it anyway to ensure our logic isn't modifying
|
158
157
|
# attributes that don't need modifying.
|
159
158
|
#
|
160
|
-
{tag: "div", attr: "name", unescaped: true},
|
159
|
+
{ tag: "div", attr: "name", unescaped: true },
|
161
160
|
].each do |config|
|
162
|
-
|
163
161
|
define_method "test_uri_escaping_of_#{config[:attr]}_attr_in_#{config[:tag]}_tag" do
|
164
162
|
html = %{<#{config[:tag]} #{config[:attr]}='examp<!--" unsafeattr=foo()>-->le.com'>test</#{config[:tag]}>}
|
165
163
|
|
@@ -190,14 +188,32 @@ class IntegrationTestAdHoc < Loofah::TestCase
|
|
190
188
|
end
|
191
189
|
end
|
192
190
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
it "sanitizes
|
198
|
-
|
191
|
+
context "xss protection from svg animate attributes" do
|
192
|
+
# see recommendation from https://html5sec.org/#137
|
193
|
+
# to sanitize "to", "from", "values", and "by" attributes
|
194
|
+
|
195
|
+
it "sanitizes 'from', 'to', and 'by' attributes" do
|
196
|
+
# for CVE-2018-16468
|
197
|
+
# see:
|
198
|
+
# - https://github.com/flavorjones/loofah/issues/154
|
199
|
+
# - https://hackerone.com/reports/429267
|
200
|
+
html = %Q{<svg><a xmlns:xlink=http://www.w3.org/1999/xlink xlink:href=?><circle r=400 /><animate attributeName=xlink:href begin=0 from=javascript:alert(1) to=%26 by=5>}
|
201
|
+
|
199
202
|
sanitized = Loofah.scrub_fragment(html, :escape)
|
200
203
|
assert_nil sanitized.at_css("animate")["from"]
|
204
|
+
assert_nil sanitized.at_css("animate")["to"]
|
205
|
+
assert_nil sanitized.at_css("animate")["by"]
|
206
|
+
end
|
207
|
+
|
208
|
+
it "sanitizes 'values' attribute" do
|
209
|
+
# for CVE-2019-15587
|
210
|
+
# see:
|
211
|
+
# - https://github.com/flavorjones/loofah/issues/171
|
212
|
+
# - https://hackerone.com/reports/709009
|
213
|
+
html = %Q{<svg> <animate href="#foo" attributeName="href" values="javascript:alert('xss')"/> <a id="foo"> <circle r=400 /> </a> </svg>}
|
214
|
+
|
215
|
+
sanitized = Loofah.scrub_fragment(html, :escape)
|
216
|
+
assert_nil sanitized.at_css("animate")["values"]
|
201
217
|
end
|
202
218
|
end
|
203
219
|
end
|
data/test/unit/test_helpers.rb
CHANGED
@@ -44,17 +44,17 @@ class UnitTestHelpers < Loofah::TestCase
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
describe "
|
47
|
+
describe "SafeListSanitizer#sanitize" do
|
48
48
|
it "calls .sanitize" do
|
49
49
|
mock(Loofah::Helpers).sanitize("foobar")
|
50
|
-
Loofah::Helpers::ActionView::
|
50
|
+
Loofah::Helpers::ActionView::SafeListSanitizer.new.sanitize "foobar"
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
describe "
|
54
|
+
describe "SafeListSanitizer#sanitize_css" do
|
55
55
|
it "calls .sanitize_css" do
|
56
56
|
mock(Loofah::Helpers).sanitize_css("foobar")
|
57
|
-
Loofah::Helpers::ActionView::
|
57
|
+
Loofah::Helpers::ActionView::SafeListSanitizer.new.sanitize_css "foobar"
|
58
58
|
end
|
59
59
|
end
|
60
60
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: loofah
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Dalessio
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2019-10-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
@@ -43,16 +43,16 @@ dependencies:
|
|
43
43
|
name: rake
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- - "
|
46
|
+
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: '
|
48
|
+
version: '12.3'
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
|
-
- - "
|
53
|
+
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
55
|
+
version: '12.3'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: minitest
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -85,86 +85,86 @@ dependencies:
|
|
85
85
|
name: json
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
|
-
- - "
|
88
|
+
- - "~>"
|
89
89
|
- !ruby/object:Gem::Version
|
90
|
-
version:
|
90
|
+
version: 2.2.0
|
91
91
|
type: :development
|
92
92
|
prerelease: false
|
93
93
|
version_requirements: !ruby/object:Gem::Requirement
|
94
94
|
requirements:
|
95
|
-
- - "
|
95
|
+
- - "~>"
|
96
96
|
- !ruby/object:Gem::Version
|
97
|
-
version:
|
97
|
+
version: 2.2.0
|
98
98
|
- !ruby/object:Gem::Dependency
|
99
99
|
name: hoe-gemspec
|
100
100
|
requirement: !ruby/object:Gem::Requirement
|
101
101
|
requirements:
|
102
|
-
- - "
|
102
|
+
- - "~>"
|
103
103
|
- !ruby/object:Gem::Version
|
104
|
-
version: '0'
|
104
|
+
version: '1.0'
|
105
105
|
type: :development
|
106
106
|
prerelease: false
|
107
107
|
version_requirements: !ruby/object:Gem::Requirement
|
108
108
|
requirements:
|
109
|
-
- - "
|
109
|
+
- - "~>"
|
110
110
|
- !ruby/object:Gem::Version
|
111
|
-
version: '0'
|
111
|
+
version: '1.0'
|
112
112
|
- !ruby/object:Gem::Dependency
|
113
113
|
name: hoe-debugging
|
114
114
|
requirement: !ruby/object:Gem::Requirement
|
115
115
|
requirements:
|
116
|
-
- - "
|
116
|
+
- - "~>"
|
117
117
|
- !ruby/object:Gem::Version
|
118
|
-
version: '0'
|
118
|
+
version: '2.0'
|
119
119
|
type: :development
|
120
120
|
prerelease: false
|
121
121
|
version_requirements: !ruby/object:Gem::Requirement
|
122
122
|
requirements:
|
123
|
-
- - "
|
123
|
+
- - "~>"
|
124
124
|
- !ruby/object:Gem::Version
|
125
|
-
version: '0'
|
125
|
+
version: '2.0'
|
126
126
|
- !ruby/object:Gem::Dependency
|
127
127
|
name: hoe-bundler
|
128
128
|
requirement: !ruby/object:Gem::Requirement
|
129
129
|
requirements:
|
130
|
-
- - "
|
130
|
+
- - "~>"
|
131
131
|
- !ruby/object:Gem::Version
|
132
|
-
version: '
|
132
|
+
version: '1.5'
|
133
133
|
type: :development
|
134
134
|
prerelease: false
|
135
135
|
version_requirements: !ruby/object:Gem::Requirement
|
136
136
|
requirements:
|
137
|
-
- - "
|
137
|
+
- - "~>"
|
138
138
|
- !ruby/object:Gem::Version
|
139
|
-
version: '
|
139
|
+
version: '1.5'
|
140
140
|
- !ruby/object:Gem::Dependency
|
141
141
|
name: hoe-git
|
142
142
|
requirement: !ruby/object:Gem::Requirement
|
143
143
|
requirements:
|
144
|
-
- - "
|
144
|
+
- - "~>"
|
145
145
|
- !ruby/object:Gem::Version
|
146
|
-
version: '
|
146
|
+
version: '1.6'
|
147
147
|
type: :development
|
148
148
|
prerelease: false
|
149
149
|
version_requirements: !ruby/object:Gem::Requirement
|
150
150
|
requirements:
|
151
|
-
- - "
|
151
|
+
- - "~>"
|
152
152
|
- !ruby/object:Gem::Version
|
153
|
-
version: '
|
153
|
+
version: '1.6'
|
154
154
|
- !ruby/object:Gem::Dependency
|
155
155
|
name: concourse
|
156
156
|
requirement: !ruby/object:Gem::Requirement
|
157
157
|
requirements:
|
158
158
|
- - ">="
|
159
159
|
- !ruby/object:Gem::Version
|
160
|
-
version: 0.
|
160
|
+
version: 0.26.0
|
161
161
|
type: :development
|
162
162
|
prerelease: false
|
163
163
|
version_requirements: !ruby/object:Gem::Requirement
|
164
164
|
requirements:
|
165
165
|
- - ">="
|
166
166
|
- !ruby/object:Gem::Version
|
167
|
-
version: 0.
|
167
|
+
version: 0.26.0
|
168
168
|
- !ruby/object:Gem::Dependency
|
169
169
|
name: rdoc
|
170
170
|
requirement: !ruby/object:Gem::Requirement
|
@@ -191,26 +191,20 @@ dependencies:
|
|
191
191
|
requirements:
|
192
192
|
- - "~>"
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version: '3.
|
194
|
+
version: '3.18'
|
195
195
|
type: :development
|
196
196
|
prerelease: false
|
197
197
|
version_requirements: !ruby/object:Gem::Requirement
|
198
198
|
requirements:
|
199
199
|
- - "~>"
|
200
200
|
- !ruby/object:Gem::Version
|
201
|
-
version: '3.
|
201
|
+
version: '3.18'
|
202
202
|
description: |-
|
203
|
-
Loofah is a general library for manipulating and transforming HTML/XML
|
204
|
-
documents and fragments. It's built on top of Nokogiri and libxml2, so
|
205
|
-
it's fast and has a nice API.
|
203
|
+
Loofah is a general library for manipulating and transforming HTML/XML documents and fragments, built on top of Nokogiri.
|
206
204
|
|
207
|
-
Loofah excels at HTML sanitization (XSS prevention). It includes some
|
208
|
-
nice HTML sanitizers, which are based on HTML5lib's whitelist, so it
|
209
|
-
most likely won't make your codes less secure. (These statements have
|
210
|
-
not been evaluated by Netexperts.)
|
205
|
+
Loofah excels at HTML sanitization (XSS prevention). It includes some nice HTML sanitizers, which are based on HTML5lib's safelist, so it most likely won't make your codes less secure. (These statements have not been evaluated by Netexperts.)
|
211
206
|
|
212
|
-
ActiveRecord extensions for sanitization are available in the
|
213
|
-
[`loofah-activerecord` gem](https://github.com/flavorjones/loofah-activerecord).
|
207
|
+
ActiveRecord extensions for sanitization are available in the [`loofah-activerecord` gem](https://github.com/flavorjones/loofah-activerecord).
|
214
208
|
email:
|
215
209
|
- mike.dalessio@gmail.com
|
216
210
|
- bryan@brynary.com
|
@@ -241,8 +235,8 @@ files:
|
|
241
235
|
- lib/loofah/html/document.rb
|
242
236
|
- lib/loofah/html/document_fragment.rb
|
243
237
|
- lib/loofah/html5/libxml2_workarounds.rb
|
238
|
+
- lib/loofah/html5/safelist.rb
|
244
239
|
- lib/loofah/html5/scrub.rb
|
245
|
-
- lib/loofah/html5/whitelist.rb
|
246
240
|
- lib/loofah/instance_methods.rb
|
247
241
|
- lib/loofah/metahelpers.rb
|
248
242
|
- lib/loofah/scrubber.rb
|
@@ -253,6 +247,7 @@ files:
|
|
253
247
|
- test/assets/testdata_sanitizer_tests1.dat
|
254
248
|
- test/helper.rb
|
255
249
|
- test/html5/test_sanitizer.rb
|
250
|
+
- test/html5/test_scrub.rb
|
256
251
|
- test/integration/test_ad_hoc.rb
|
257
252
|
- test/integration/test_helpers.rb
|
258
253
|
- test/integration/test_html.rb
|
@@ -284,10 +279,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
284
279
|
- !ruby/object:Gem::Version
|
285
280
|
version: '0'
|
286
281
|
requirements: []
|
287
|
-
|
288
|
-
rubygems_version: 2.7.7
|
282
|
+
rubygems_version: 3.0.3
|
289
283
|
signing_key:
|
290
284
|
specification_version: 4
|
291
285
|
summary: Loofah is a general library for manipulating and transforming HTML/XML documents
|
292
|
-
and fragments
|
286
|
+
and fragments, built on top of Nokogiri
|
293
287
|
test_files: []
|