Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package rubygem-rails-html-sanitizer for
openSUSE:Factory checked in at 2026-04-17 21:04:20
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-rails-html-sanitizer (Old)
and /work/SRC/openSUSE:Factory/.rubygem-rails-html-sanitizer.new.11940
(New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-rails-html-sanitizer"
Fri Apr 17 21:04:20 2026 rev:13 rq:1347656 version:1.7.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/rubygem-rails-html-sanitizer/rubygem-rails-html-sanitizer.changes
2023-11-17 20:50:22.178965387 +0100
+++
/work/SRC/openSUSE:Factory/.rubygem-rails-html-sanitizer.new.11940/rubygem-rails-html-sanitizer.changes
2026-04-17 21:04:52.579354487 +0200
@@ -1,0 +2,51 @@
+Fri Mar 13 08:43:49 UTC 2026 - Johannes Segitz <[email protected]>
+
+- Update to version 1.7.0
+ * Add Rails::HTML::Sanitizer.allowed_uri? which delegates to
+ Loofah::HTML5::Scrub.allowed_uri?, allowing the Rails framework to check
+ URI safety without a direct dependency on Loofah.
+ * The minimum Loofah dependency is now ~> 2.25.
+
+-------------------------------------------------------------------
+Mon Dec 16 14:03:38 UTC 2024 - Paolo Perego <[email protected]>
+
+- Update to version 1.6.2
+ * PermitScrubber fully supports frozen "allowed tags".
+ - v1.6.1 introduced safety checks that may remove unsafe tags from the
+ allowed list, which introduced a regression for applications passing
+ a frozen array of allowed tags. Tags and attributes are now properly
+ copied when they are passed to the scrubber.
+
+- Version 1.6.1
+
+ * The dependency on Nokogiri is updated to v1.15.7 or >=1.16.8. This change
+ addresses CVE-2024-53985 (GHSA-w8gc-x259-rc7x).
+
+ * Disallowed tags will be pruned when they appear in foreign content (i.e.
+ SVG or MathML content), regardless of the prune: option value.
Previously,
+ disallowed tags were "stripped" unless the gem was configured with the
+ prune: true option.
+
+ The CVEs addressed by this change are:
+ * CVE-2024-53986 (GHSA-638j-pmjw-jq48)
+ * CVE-2024-53987 (GHSA-2x5m-9ch4-qgrr)
+
+ * The tags "noscript", "mglyph", and "malignmark" will not be allowed, even
+ if explicitly added to the allowlist. If applications try to allow any of
+ these tags, a warning is emitted and the tags are removed from the
+ allow-list.
+
+ The CVEs addressed by this change are:
+ * CVE-2024-53988 (GHSA-cfjx-w229-hgx5)
+ * CVE-2024-53989 (GHSA-rxv5-gxqc-xx8g)
+
+ Please note that we may restore support for allowing "noscript" in a
future
+ release. We do not expect to ever allow "mglyph" or "malignmark", though,
+ especially since browser support is minimal for these tags.
+
+ * Improve performance by eliminating needless operations on attributes that
+ are being removed.
+
+*Mike Dalessio*
+
+-------------------------------------------------------------------
Old:
----
rails-html-sanitizer-1.6.0.gem
New:
----
rails-html-sanitizer-1.7.0.gem
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ rubygem-rails-html-sanitizer.spec ++++++
--- /var/tmp/diff_new_pack.FLZQR1/_old 2026-04-17 21:04:53.239381670 +0200
+++ /var/tmp/diff_new_pack.FLZQR1/_new 2026-04-17 21:04:53.239381670 +0200
@@ -1,7 +1,7 @@
#
# spec file for package rubygem-rails-html-sanitizer
#
-# Copyright (c) 2023 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -24,7 +24,7 @@
#
Name: rubygem-rails-html-sanitizer
-Version: 1.6.0
+Version: 1.7.0
Release: 0
%define mod_name rails-html-sanitizer
%define mod_full_name %{mod_name}-%{version}
++++++ rails-html-sanitizer-1.6.0.gem -> rails-html-sanitizer-1.7.0.gem ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/CHANGELOG.md new/CHANGELOG.md
--- old/CHANGELOG.md 2023-05-26 15:20:35.000000000 +0200
+++ new/CHANGELOG.md 1980-01-02 01:00:00.000000000 +0100
@@ -1,3 +1,67 @@
+## v1.7.0 / 2026-02-24
+
+* Add `Rails::HTML::Sanitizer.allowed_uri?` which delegates to
`Loofah::HTML5::Scrub.allowed_uri?`,
+ allowing the Rails framework to check URI safety without a direct dependency
on Loofah.
+
+ The minimum Loofah dependency is now `~> 2.25`.
+
+ *Mike Dalessio*
+
+
+## v1.6.2 / 2024-12-12
+
+* `PermitScrubber` fully supports frozen "allowed tags".
+
+ v1.6.1 introduced safety checks that may remove unsafe tags from the allowed
list, which
+ introduced a regression for applications passing a frozen array of allowed
tags. Tags and
+ attributes are now properly copied when they are passed to the scrubber.
+
+ Fixes #195.
+
+ *Mike Dalessio*
+
+
+## 1.6.1 / 2024-12-02
+
+This is a performance and security release which addresses several possible
XSS vulnerabilities.
+
+* The dependency on Nokogiri is updated to v1.15.7 or >=1.16.8.
+
+ This change addresses CVE-2024-53985 (GHSA-w8gc-x259-rc7x).
+
+ *Mike Dalessio*
+
+* Disallowed tags will be pruned when they appear in foreign content (i.e. SVG
or MathML content),
+ regardless of the `prune:` option value. Previously, disallowed tags were
"stripped" unless the
+ gem was configured with the `prune: true` option.
+
+ The CVEs addressed by this change are:
+
+ - CVE-2024-53986 (GHSA-638j-pmjw-jq48)
+ - CVE-2024-53987 (GHSA-2x5m-9ch4-qgrr)
+
+ *Mike Dalessio*
+
+* The tags "noscript", "mglyph", and "malignmark" will not be allowed, even if
explicitly added to
+ the allowlist. If applications try to allow any of these tags, a warning is
emitted and the tags
+ are removed from the allow-list.
+
+ The CVEs addressed by this change are:
+
+ - CVE-2024-53988 (GHSA-cfjx-w229-hgx5)
+ - CVE-2024-53989 (GHSA-rxv5-gxqc-xx8g)
+
+ Please note that we _may_ restore support for allowing "noscript" in a
future release. We do not
+ expect to ever allow "mglyph" or "malignmark", though, especially since
browser support is minimal
+ for these tags.
+
+ *Mike Dalessio*
+
+* Improve performance by eliminating needless operations on attributes that
are being removed. #188
+
+ *Mike Dalessio*
+
+
## 1.6.0 / 2023-05-26
* Dependencies have been updated:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/README.md new/README.md
--- old/README.md 2023-05-26 15:20:35.000000000 +0200
+++ new/README.md 1980-01-02 01:00:00.000000000 +0100
@@ -30,10 +30,6 @@
# => Bold no more! See more here...
```
-HTML5 version:
-
-
-
#### LinkSanitizer
```ruby
Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/rails/html/sanitizer/version.rb
new/lib/rails/html/sanitizer/version.rb
--- old/lib/rails/html/sanitizer/version.rb 2023-05-26 15:20:35.000000000
+0200
+++ new/lib/rails/html/sanitizer/version.rb 1980-01-02 01:00:00.000000000
+0100
@@ -3,7 +3,7 @@
module Rails
module HTML
class Sanitizer
- VERSION = "1.6.0"
+ VERSION = "1.7.0"
end
end
end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/rails/html/sanitizer.rb
new/lib/rails/html/sanitizer.rb
--- old/lib/rails/html/sanitizer.rb 2023-05-26 15:20:35.000000000 +0200
+++ new/lib/rails/html/sanitizer.rb 1980-01-02 01:00:00.000000000 +0100
@@ -13,6 +13,10 @@
def best_supported_vendor
html5_support? ? Rails::HTML5::Sanitizer : Rails::HTML4::Sanitizer
end
+
+ def allowed_uri?(uri_string)
+ Loofah::HTML5::Scrub.allowed_uri?(uri_string)
+ end
end
def sanitize(html, options = {})
@@ -106,6 +110,7 @@
"ins",
"kbd",
"li",
+ "mark",
"ol",
"p",
"pre",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/rails/html/scrubbers.rb
new/lib/rails/html/scrubbers.rb
--- old/lib/rails/html/scrubbers.rb 2023-05-26 15:20:35.000000000 +0200
+++ new/lib/rails/html/scrubbers.rb 1980-01-02 01:00:00.000000000 +0100
@@ -56,11 +56,11 @@
end
def tags=(tags)
- @tags = validate!(tags, :tags)
+ @tags = validate!(tags.dup, :tags)
end
def attributes=(attributes)
- @attributes = validate!(attributes, :attributes)
+ @attributes = validate!(attributes.dup, :attributes)
end
def scrub(node)
@@ -72,10 +72,11 @@
return CONTINUE if skip_node?(node)
unless (node.element? || node.comment?) && keep_node?(node)
- return STOP if scrub_node(node) == STOP
+ return STOP unless scrub_node(node) == CONTINUE
end
scrub_attributes(node)
+ CONTINUE
end
protected
@@ -100,15 +101,22 @@
end
def scrub_node(node)
- node.before(node.children) unless prune # strip
+ # If a node has a namespace, then it's a tag in either a `math` or
`svg` foreign context,
+ # and we should always prune it to avoid namespace confusion and
mutation XSS vectors.
+ unless prune || node.namespace
+ node.before(node.children)
+ end
node.remove
end
def scrub_attributes(node)
if @attributes
node.attribute_nodes.each do |attr|
- attr.remove if scrub_attribute?(attr.name)
- scrub_attribute(node, attr)
+ if scrub_attribute?(attr.name)
+ attr.remove
+ else
+ scrub_attribute(node, attr)
+ end
end
scrub_css_attribute(node)
@@ -130,6 +138,24 @@
if var && !var.is_a?(Enumerable)
raise ArgumentError, "You should pass :#{name} as an Enumerable"
end
+
+ if var && name == :tags
+ if var.include?("mglyph")
+ warn("WARNING: 'mglyph' tags cannot be allowed by the
PermitScrubber and will be scrubbed")
+ var.delete("mglyph")
+ end
+
+ if var.include?("malignmark")
+ warn("WARNING: 'malignmark' tags cannot be allowed by the
PermitScrubber and will be scrubbed")
+ var.delete("malignmark")
+ end
+
+ if var.include?("noscript")
+ warn("WARNING: 'noscript' tags cannot be allowed by the
PermitScrubber and will be scrubbed")
+ var.delete("noscript")
+ end
+ end
+
var
end
@@ -140,9 +166,7 @@
attr_node.node_name
end
- if Loofah::HTML5::SafeList::ATTR_VAL_IS_URI.include?(attr_name)
- return if Loofah::HTML5::Scrub.scrub_uri_attribute(attr_node)
- end
+ return if
Loofah::HTML5::SafeList::ATTR_VAL_IS_URI.include?(attr_name) &&
Loofah::HTML5::Scrub.scrub_uri_attribute(attr_node)
if
Loofah::HTML5::SafeList::SVG_ATTR_VAL_ALLOWS_REF.include?(attr_name)
Loofah::HTML5::Scrub.scrub_attribute_that_allows_local_ref(attr_node)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata 2023-05-26 15:20:35.000000000 +0200
+++ new/metadata 1980-01-02 01:00:00.000000000 +0100
@@ -1,16 +1,15 @@
--- !ruby/object:Gem::Specification
name: rails-html-sanitizer
version: !ruby/object:Gem::Version
- version: 1.6.0
+ version: 1.7.0
platform: ruby
authors:
- Rafael Mendonça França
- Kasper Timm Hansen
- Mike Dalessio
-autorequire:
bindir: bin
cert_chain: []
-date: 2023-05-26 00:00:00.000000000 Z
+date: 1980-01-02 00:00:00.000000000 Z
dependencies:
- !ruby/object:Gem::Dependency
name: loofah
@@ -18,28 +17,82 @@
requirements:
- - "~>"
- !ruby/object:Gem::Version
- version: '2.21'
+ version: '2.25'
type: :runtime
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - "~>"
- !ruby/object:Gem::Version
- version: '2.21'
+ version: '2.25'
- !ruby/object:Gem::Dependency
name: nokogiri
requirement: !ruby/object:Gem::Requirement
requirements:
- - - "~>"
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: 1.15.7
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.0
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.0.rc1
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.1
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.2
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.3
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.4
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.5
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.6
+ - - "!="
- !ruby/object:Gem::Version
- version: '1.14'
+ version: 1.16.7
type: :runtime
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - - "~>"
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: 1.15.7
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.0
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.0.rc1
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.1
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.2
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.3
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.4
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.5
+ - - "!="
+ - !ruby/object:Gem::Version
+ version: 1.16.6
+ - - "!="
- !ruby/object:Gem::Version
- version: '1.14'
+ version: 1.16.7
description: HTML sanitization for Rails applications
email:
- [email protected]
@@ -59,15 +112,15 @@
- test/rails_api_test.rb
- test/sanitizer_test.rb
- test/scrubbers_test.rb
+- test/test_helper.rb
homepage: https://github.com/rails/rails-html-sanitizer
licenses:
- MIT
metadata:
bug_tracker_uri: https://github.com/rails/rails-html-sanitizer/issues
- changelog_uri:
https://github.com/rails/rails-html-sanitizer/blob/v1.6.0/CHANGELOG.md
- documentation_uri: https://www.rubydoc.info/gems/rails-html-sanitizer/1.6.0
- source_code_uri: https://github.com/rails/rails-html-sanitizer/tree/v1.6.0
-post_install_message:
+ changelog_uri:
https://github.com/rails/rails-html-sanitizer/blob/v1.7.0/CHANGELOG.md
+ documentation_uri: https://www.rubydoc.info/gems/rails-html-sanitizer/1.7.0
+ source_code_uri: https://github.com/rails/rails-html-sanitizer/tree/v1.7.0
rdoc_options: []
require_paths:
- lib
@@ -82,11 +135,11 @@
- !ruby/object:Gem::Version
version: '0'
requirements: []
-rubygems_version: 3.4.10
-signing_key:
+rubygems_version: 4.0.3
specification_version: 4
summary: This gem is responsible to sanitize HTML fragments in Rails
applications.
test_files:
- test/rails_api_test.rb
- test/sanitizer_test.rb
- test/scrubbers_test.rb
+- test/test_helper.rb
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/test/rails_api_test.rb new/test/rails_api_test.rb
--- old/test/rails_api_test.rb 2023-05-26 15:20:35.000000000 +0200
+++ new/test/rails_api_test.rb 1980-01-02 01:00:00.000000000 +0100
@@ -1,7 +1,6 @@
# frozen_string_literal: true
-require "minitest/autorun"
-require "rails-html-sanitizer"
+require_relative "test_helper"
class RailsApiTest < Minitest::Test
def test_html_module_name_alias
@@ -85,4 +84,18 @@
skip("no HTML5 support on this platform") unless
Rails::HTML::Sanitizer.html5_support?
assert_equal(Rails::HTML5::SafeListSanitizer,
Rails::HTML5::Sanitizer.white_list_sanitizer)
end
+
+ def test_allowed_uri_returns_true_for_allowed_protocols
+ assert(Rails::HTML::Sanitizer.allowed_uri?("https://example.com"))
+ assert(Rails::HTML::Sanitizer.allowed_uri?("http://example.com"))
+ assert(Rails::HTML::Sanitizer.allowed_uri?("mailto:[email protected]"))
+ end
+
+ def test_allowed_uri_returns_false_for_disallowed_protocols
+ refute(Rails::HTML::Sanitizer.allowed_uri?("javascript:alert(1)"))
+ end
+
+ def test_allowed_uri_returns_true_for_relative_uris
+ assert(Rails::HTML::Sanitizer.allowed_uri?("/relative/path"))
+ end
end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/test/sanitizer_test.rb new/test/sanitizer_test.rb
--- old/test/sanitizer_test.rb 2023-05-26 15:20:35.000000000 +0200
+++ new/test/sanitizer_test.rb 1980-01-02 01:00:00.000000000 +0100
@@ -1,10 +1,6 @@
# frozen_string_literal: true
-require "minitest/autorun"
-require "rails-html-sanitizer"
-
-puts "nokogiri version info: #{Nokogiri::VERSION_INFO}"
-puts "html5 support: #{Rails::HTML::Sanitizer.html5_support?}"
+require_relative "test_helper"
#
# NOTE that many of these tests contain multiple acceptable results.
@@ -728,8 +724,6 @@
end
def test_uri_escaping_of_href_attr_in_a_tag_in_safe_list_sanitizer
- skip if RUBY_VERSION < "2.3"
-
html = %{<a href='examp<!--" unsafeattr=foo()>-->le.com'>test</a>}
text = safe_list_sanitize(html)
@@ -747,8 +741,6 @@
end
def test_uri_escaping_of_src_attr_in_a_tag_in_safe_list_sanitizer
- skip if RUBY_VERSION < "2.3"
-
html = %{<a src='examp<!--" unsafeattr=foo()>-->le.com'>test</a>}
text = safe_list_sanitize(html)
@@ -766,8 +758,6 @@
end
def test_uri_escaping_of_name_attr_in_a_tag_in_safe_list_sanitizer
- skip if RUBY_VERSION < "2.3"
-
html = %{<a name='examp<!--" unsafeattr=foo()>-->le.com'>test</a>}
text = safe_list_sanitize(html)
@@ -785,8 +775,6 @@
end
def test_uri_escaping_of_name_action_in_a_tag_in_safe_list_sanitizer
- skip if RUBY_VERSION < "2.3"
-
html = %{<a action='examp<!--" unsafeattr=foo()>-->le.com'>test</a>}
text = safe_list_sanitize(html, attributes: ["action"])
@@ -926,7 +914,7 @@
# libxml2
"<svg><style><script>alert(1)</script></style></svg>",
# libgumbo
- "<svg><style>alert(1)</style></svg>"
+ "<svg><style></style></svg>",
]
assert_includes(acceptable_results, actual)
@@ -984,6 +972,76 @@
assert_includes(acceptable_results, actual)
end
+ def test_combination_of_svg_and_style_with_escaped_img_payload
+ # https://hackerone.com/reports/2503220
+ input, tags = "<svg><style><img src onerror=alert(1)>", ["svg",
"style"]
+ actual = safe_list_sanitize(input, tags: tags)
+ acceptable_results = [
+ # libxml2
+ "<svg><style>&lt;img src onerror=alert(1)></style></svg>",
+ # libgumbo
+ "<svg><style><img src onerror=alert(1)></style></svg>",
+ ]
+
+ assert_includes(acceptable_results, actual)
+ end
+
+ def test_combination_of_math_and_style_with_escaped_img_payload
+ # https://hackerone.com/reports/2503220
+ input, tags = "<math><style><img src onerror=alert(1)>", ["math",
"style"]
+ actual = safe_list_sanitize(input, tags: tags)
+ acceptable_results = [
+ # libxml2
+ "<math><style>&lt;img src onerror=alert(1)></style></math>",
+ # libgumbo
+ "<math><style><img src onerror=alert(1)></style></math>",
+ ]
+
+ assert_includes(acceptable_results, actual)
+ end
+
+ def test_combination_of_style_and_disallowed_svg_with_script_payload
+ # https://hackerone.com/reports/2519936
+ input, tags = "<svg><style><style
class='</style><script>alert(1)</script>'>", ["style"]
+ actual = safe_list_sanitize(input, tags: tags)
+ acceptable_results = [
+ # libxml2
+ "<style><style class='</style>alert(1)'>",
+ # libgumbo
+ "",
+ ]
+
+ assert_includes(acceptable_results, actual)
+ end
+
+ def test_combination_of_style_and_disallowed_math_with_script_payload
+ # https://hackerone.com/reports/2519936
+ input, tags = "<math><style><style
class='</style><script>alert(1)</script>'>", ["style"]
+ actual = safe_list_sanitize(input, tags: tags)
+ acceptable_results = [
+ # libxml2
+ "<style><style class='</style>alert(1)'>",
+ # libgumbo
+ "",
+ ]
+
+ assert_includes(acceptable_results, actual)
+ end
+
+ def test_math_with_disallowed_mtext_and_img_payload
+ # https://hackerone.com/reports/2519941
+ input, tags = "<math><mtext><table><mglyph><style><img src=:
onerror=alert(1)>", ["math", "style"]
+ actual = safe_list_sanitize(input, tags: tags)
+ acceptable_results = [
+ # libxml2
+ "<math><style><img src=: onerror=alert(1)></style></math>",
+ # libgumbo
+ "<math></math>",
+ ]
+
+ assert_includes(acceptable_results, actual)
+ end
+
def test_should_sanitize_illegal_style_properties
raw = %(display:block; position:absolute; left:0; top:0;
width:100%; height:100%; z-index:1; background-color:black;
background-image:url(http://www.ragingplatypus.com/i/cam-full.jpg);
background-x:center; background-y:center; background-repeat:repeat;)
expected =
%(display:block;width:100%;height:100%;background-color:black;background-x:center;background-y:center;)
@@ -1034,6 +1092,66 @@
assert_equal "", sanitize_css(raw)
end
+ def test_should_prune_mglyph
+ # https://hackerone.com/reports/2519936
+ input = "<math><mtext><table><mglyph><style><img src=: onerror=alert(1)>"
+ tags = %w(math mtext table mglyph style).freeze
+
+ actual = nil
+ assert_output(nil, /WARNING: 'mglyph' tags cannot be allowed by the
PermitScrubber/) do
+ actual = safe_list_sanitize(input, tags: tags)
+ end
+
+ acceptable_results = [
+ # libxml2
+ "<math><mtext><table><style><img src=:
onerror=alert(1)></style></table></mtext></math>",
+ # libgumbo
+ "<math><mtext><style><img src=:
onerror=alert(1)></style><table></table></mtext></math>",
+ ]
+
+ assert_includes(acceptable_results, actual)
+ end
+
+ def test_should_prune_malignmark
+ # https://hackerone.com/reports/2519936
+ input = "<math><mtext><table><malignmark><style><img src=:
onerror=alert(1)>"
+ tags = %w(math mtext table malignmark style).freeze
+
+ actual = nil
+ assert_output(nil, /WARNING: 'malignmark' tags cannot be allowed by the
PermitScrubber/) do
+ actual = safe_list_sanitize(input, tags: tags)
+ end
+
+ acceptable_results = [
+ # libxml2
+ "<math><mtext><table><style><img src=:
onerror=alert(1)></style></table></mtext></math>",
+ # libgumbo
+ "<math><mtext><style><img src=:
onerror=alert(1)></style><table></table></mtext></math>",
+ ]
+
+ assert_includes(acceptable_results, actual)
+ end
+
+ def test_should_prune_noscript
+ # https://hackerone.com/reports/2509647
+ input = "<div><noscript><p
id='</noscript><script>alert(1)</script>'></noscript>"
+ tags = ["p", "div", "noscript"].freeze
+
+ actual = nil
+ assert_output(nil, /WARNING: 'noscript' tags cannot be allowed by the
PermitScrubber/) do
+ actual = safe_list_sanitize(input, tags: tags, attributes: %w(id))
+ end
+
+ acceptable_results = [
+ # libxml2
+ "<div><p
id=\"</noscript><script>alert(1)</script>\"></p></div>",
+ # libgumbo
+ "<div><p id=\"</noscript><script>alert(1)</script>\"></p></div>",
+ ]
+
+ assert_includes(acceptable_results, actual)
+ end
+
protected
def safe_list_sanitize(input, options = {})
module_under_test::SafeListSanitizer.new.sanitize(input, options)
@@ -1083,5 +1201,84 @@
class HTML5SafeListSanitizerTest < Minitest::Test
@module_under_test = Rails::HTML5
include SafeListSanitizerTest
+
+ def
test_should_not_be_vulnerable_to_nokogiri_foreign_style_serialization_bug
+ # https://hackerone.com/reports/2503220
+ input = "<svg><style><img src onerror=alert(1)>"
+ result = Rails::HTML5::SafeListSanitizer.new.sanitize(input, tags:
["svg", "style"])
+ browser = Nokogiri::HTML5::Document.parse(result)
+ xss = browser.at_xpath("//img/@onerror")
+
+ assert_nil(xss)
+ end
+
+ def test_should_not_be_vulnerable_to_ns_confusion_2519936
+ # https://hackerone.com/reports/2519936
+ input = "<math><style><style class='</style><script>alert(1)</script>'>"
+ result = Rails::HTML5::SafeListSanitizer.new.sanitize(input, tags:
["style"])
+ browser = Nokogiri::HTML5::Document.parse(result)
+ xss = browser.at_xpath("//script")
+
+ assert_nil(xss)
+ end
+
+ def test_should_not_be_vulnerable_to_ns_confusion_2519941
+ # https://hackerone.com/reports/2519941
+ input = "<math><mtext><table><mglyph><style><img src=: onerror=alert(1)>"
+ result = Rails::HTML5::SafeListSanitizer.new.sanitize(input, tags:
%w(math style))
+ browser = Nokogiri::HTML5::Document.parse(result)
+ xss = browser.at_xpath("//img/@onerror")
+
+ assert_nil(xss)
+ end
+
+ def test_should_not_be_vulnerable_to_mglyph_namespace_confusion
+ # https://hackerone.com/reports/2519936
+ input = "<math><mtext><table><mglyph><style><img src=: onerror=alert(1)>"
+ tags = %w(math mtext table mglyph style)
+
+ result = nil
+ assert_output(nil, /WARNING/) do
+ result = safe_list_sanitize(input, tags: tags)
+ end
+
+ browser = Nokogiri::HTML5::Document.parse(result)
+ xss = browser.at_xpath("//img/@onerror")
+
+ assert_nil(xss)
+ end
+
+ def test_should_not_be_vulnerable_to_malignmark_namespace_confusion
+ # https://hackerone.com/reports/2519936
+ input = "<math><mtext><table><malignmark><style><img src=:
onerror=alert(1)>"
+ tags = %w(math mtext table malignmark style)
+
+ result = nil
+ assert_output(nil, /WARNING/) do
+ result = safe_list_sanitize(input, tags: tags)
+ end
+
+ browser = Nokogiri::HTML5::Document.parse(result)
+ xss = browser.at_xpath("//img/@onerror")
+
+ assert_nil(xss)
+ end
+
+ def test_should_not_be_vulnerable_to_noscript_attacks
+ # https://hackerone.com/reports/2509647
+ skip("browser assertion requires parse_noscript_content_as_text") unless
Nokogiri::VERSION >= "1.17"
+
+ input = '<noscript><p
id="</noscript><script>alert(1)</script>"></noscript>'
+
+ result = nil
+ assert_output(nil, /WARNING/) do
+ result = Rails::HTML5::SafeListSanitizer.new.sanitize(input, tags:
%w(p div noscript), attributes: %w(id class style))
+ end
+
+ browser = Nokogiri::HTML5::Document.parse(result,
parse_noscript_content_as_text: true)
+ xss = browser.at_xpath("//script")
+
+ assert_nil(xss)
+ end
end if loofah_html5_support?
end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/test/scrubbers_test.rb new/test/scrubbers_test.rb
--- old/test/scrubbers_test.rb 2023-05-26 15:20:35.000000000 +0200
+++ new/test/scrubbers_test.rb 1980-01-02 01:00:00.000000000 +0100
@@ -1,7 +1,6 @@
# frozen_string_literal: true
-require "minitest/autorun"
-require "rails-html-sanitizer"
+require_relative "test_helper"
class ScrubberTest < Minitest::Test
protected
@@ -121,6 +120,30 @@
assert_scrubbed html, '<tag></tag><tag cooler=""></tag>'
end
+ def test_does_not_allow_safelisted_mglyph
+ # https://hackerone.com/reports/2519936
+ assert_output(nil, /WARNING: 'mglyph' tags cannot be allowed by the
PermitScrubber/) do
+ @scrubber.tags = ["div", "mglyph", "span"]
+ end
+ assert_equal(["div", "span"], @scrubber.tags)
+ end
+
+ def test_does_not_allow_safelisted_malignmark
+ # https://hackerone.com/reports/2519936
+ assert_output(nil, /WARNING: 'malignmark' tags cannot be allowed by the
PermitScrubber/) do
+ @scrubber.tags = ["div", "malignmark", "span"]
+ end
+ assert_equal(["div", "span"], @scrubber.tags)
+ end
+
+ def test_does_not_allow_safelisted_noscript
+ # https://hackerone.com/reports/2509647
+ assert_output(nil, /WARNING: 'noscript' tags cannot be allowed by the
PermitScrubber/) do
+ @scrubber.tags = ["div", "noscript", "span"]
+ end
+ assert_equal(["div", "span"], @scrubber.tags)
+ end
+
def test_leaves_text
assert_scrubbed("some text")
end
@@ -207,11 +230,65 @@
end
end
- def setup
- @scrubber = ScrubStopper.new
+ class ScrubContinuer < Rails::HTML::PermitScrubber
+ def scrub_node(node)
+ Loofah::Scrubber::CONTINUE
+ end
end
def test_returns_stop_from_scrub_if_scrub_node_does
+ @scrubber = ScrubStopper.new
assert_scrub_stopped "<script>remove me</script>"
end
+
+ def test_returns_continue_from_scrub_if_scrub_node_does
+ @scrubber = ScrubContinuer.new
+ assert_node_skipped "<script>keep me</script>"
+ end
+end
+
+class PermitScrubberMinimalOperationsTest < ScrubberTest
+ class TestPermitScrubber < Rails::HTML::PermitScrubber
+ def initialize
+ @scrub_attribute_args = []
+ @scrub_attributes_args = []
+
+ super
+
+ self.tags = ["div"]
+ self.attributes = ["class"]
+ end
+
+ def scrub_attributes(node)
+ @scrub_attributes_args << node.name
+
+ super
+ end
+
+ def scrub_attribute(node, attr)
+ @scrub_attribute_args << [node.name, attr.name]
+
+ super
+ end
+ end
+
+ def test_does_not_scrub_removed_attributes
+ @scrubber = TestPermitScrubber.new
+
+ input = "<div class='foo' href='bar'></div>"
+ frag = scrub_fragment(input)
+ assert_equal("<div class=\"foo\"></div>", frag)
+
+ assert_equal([["div", "class"]],
@scrubber.instance_variable_get(:@scrub_attribute_args))
+ end
+
+ def test_does_not_scrub_attributes_of_a_removed_node
+ @scrubber = TestPermitScrubber.new
+
+ input = "<div class='foo' href='bar'><svg
xlink:href='asdf'><set></set></svg></div>"
+ frag = scrub_fragment(input)
+ assert_equal("<div class=\"foo\"></div>", frag)
+
+ assert_equal(["div"],
@scrubber.instance_variable_get(:@scrub_attributes_args))
+ end
end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/test/test_helper.rb new/test/test_helper.rb
--- old/test/test_helper.rb 1970-01-01 01:00:00.000000000 +0100
+++ new/test/test_helper.rb 1980-01-02 01:00:00.000000000 +0100
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require "minitest/autorun"
+require "rails-html-sanitizer"
+
+puts "nokogiri version info: #{Nokogiri::VERSION_INFO}"
+puts "html5 support: #{Rails::HTML::Sanitizer.html5_support?}"