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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2f00d9f256478eb753c8d211c3b25efa4204bbdbc9c5abf0415413c811a2e404
4
- data.tar.gz: 65d3871aa798dfbbfb1138b666d475b590e347cdb66614d6d39b72ad3531c742
3
+ metadata.gz: a74021096590326ee357971bec71d2c4507a95cdaf05c8e21d383ce18fee18d3
4
+ data.tar.gz: faad0d5f268dad601b633b03912e353fcc2d760fceb253d9cde2064b010b997a
5
5
  SHA512:
6
- metadata.gz: e6e31eaa72b1a2e8356aae50600ac784f85a80828cbc49ce8061384ecd3f21a1d8eaee69845dc08537c5102728c3cc41a72cb3ed8b9789c4921038398afa61e2
7
- data.tar.gz: 6b14a49842eaf4c3e0fbae5acd28fdf32a5deb6cd42f769aada848226847180c4d3a67a9dcbc439e1a4855699b0ea694cb4c7b6ee173391ac841bd334ae44b6f
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.
@@ -1,7 +1,7 @@
1
1
  module Rails
2
2
  module Html
3
3
  class Sanitizer
4
- VERSION = "1.4.3"
4
+ VERSION = "1.4.4"
5
5
  end
6
6
  end
7
7
  end
@@ -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
- if options[:tags]
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)
@@ -61,9 +61,9 @@ module Rails
61
61
  end
62
62
 
63
63
  def scrub(node)
64
- if node.cdata?
65
- text = node.document.create_text_node node.text
66
- node.replace text
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
- # this block lifted nearly verbatim from HTML5 sanitization
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
- attr_node.value = attr_node.value.gsub(/url\s*\(\s*[^#\s][^)]+?\)/m, ' ') if attr_node.value
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
@@ -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 = libxml_2_9_14_recovery? ? %{&lt;" hi} : %{ hi}
57
+ expected = libxml_2_9_14_recovery_lt? ? %{&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 = libxml_2_9_14_recovery? ? %{This is &lt;-- not\n a comment here.} : %{This is }
80
+ expected = libxml_2_9_14_recovery_lt? ? %{This is &lt;-- 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 = libxml_2_9_14_recovery? ? %{This has a &lt;![CDATA[]]&gt; here.} : %{This has a ]]&gt; here.}
86
+ expected = libxml_2_9_14_recovery_lt_bang? ? %{This has a &lt;![CDATA[]]&gt; here.} : %{This has a ]]&gt; 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 = libxml_2_9_14_recovery? ? %{This has an unclosed &lt;![CDATA[]] here...} : %{This has an unclosed ]] here...}
92
+ expected = libxml_2_9_14_recovery_lt_bang? ? %{This has an unclosed &lt;![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 = libxml_2_9_14_recovery? ? %{&lt;![CDATA[<span>section</span>]]&gt;} : %{section]]&gt;}
461
+ expected = libxml_2_9_14_recovery_lt_bang? ? %{&lt;![CDATA[<span>section</span>]]&gt;} : %{section]]&gt;}
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 = libxml_2_9_14_recovery? ? %{&lt;![CDATA[<span>neverending...</span>} : %{neverending...}
467
+ expected = libxml_2_9_14_recovery_lt_bang? ? %{&lt;![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
- def test_disallow_the_dangerous_safelist_combination_of_select_and_style
585
- input = "<select><style><script>alert(1)</script></style></select>"
586
- tags = ["select", "style"]
587
- warning = /WARNING: Rails::Html::SafeListSanitizer: removing 'style' from safelist/
588
- sanitized = nil
589
- invocation = Proc.new { sanitized = safe_list_sanitize(input, tags: tags) }
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
- if html5_mode?
592
- # if Loofah is using an HTML5 parser,
593
- # then "style" should be removed by the parser as an invalid child of "select"
594
- assert_silent(&invocation)
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)
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
- refute_includes(sanitized, "style")
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 &gt; 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 &gt; 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>&lt;script&gt;alert(1)&lt;/script&gt;</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>&lt;script&gt;alert(1)&lt;/script&gt;</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>&lt;img src=x onerror=alert(1)&gt;</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>&lt;img src=x onerror=alert(1)&gt;</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>&lt;img src=x onerror=alert(1)&gt;</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>&lt;img src=x onerror=alert(1)&gt;</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 libxml_2_9_14_recovery?
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 html5_mode?
665
- ::Loofah.respond_to?(:html5_mode?) && ::Loofah.html5_mode?
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.3
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-06-09 00:00:00.000000000 Z
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.3'
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.3'
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.3/CHANGELOG.md
107
- documentation_uri: https://www.rubydoc.info/gems/rails-html-sanitizer/1.4.3
108
- source_code_uri: https://github.com/rails/rails-html-sanitizer/tree/v1.4.3
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.5
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.