VYPR
High severityNVD Advisory· Published Jun 16, 2020· Updated Aug 4, 2024

Cross-site Scripting in Sanitize

CVE-2020-4054

Description

In Sanitize (RubyGem sanitize) greater than or equal to 3.0.0 and less than 5.2.1, there is a cross-site scripting vulnerability. When HTML is sanitized using Sanitize's "relaxed" config, or a custom config that allows certain elements, some content in a math or svg element may not be sanitized correctly even if math and svg are not in the allowlist. You are likely to be vulnerable to this issue if you use Sanitize's relaxed config or a custom config that allows one or more of the following HTML elements: iframe, math, noembed, noframes, noscript, plaintext, script, style, svg, xmp. Using carefully crafted input, an attacker may be able to sneak arbitrary HTML through Sanitize, potentially resulting in XSS (cross-site scripting) or other undesired behavior when that HTML is rendered in a browser. This has been fixed in 5.2.1.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

CVE-2020-4054 is an XSS vulnerability in Ruby Gem Sanitize versions 3.0.0 to 5.2.0, where sanitization bypass occurs in math/svg elements leading to arbitrary HTML injection.

The vulnerability lies in Sanitize's handling of HTML foreign content, specifically within ` and elements. Due to differences in parsing rules for these elements, Sanitize fails to sanitize content inside them even when math and svg` are not in the allowlist [1]. This allows attackers to inject arbitrary HTML through carefully crafted input [2].

Exploitation requires using Sanitize's "relaxed" config or a custom config that permits certain elements such as `, , , , , , , , , or ` [2]. The vulnerability affects versions 3.0.0 up to but not including 5.2.1, all versions after the gem's initial release [2].

Successful exploitation could lead to cross-site scripting (XSS) or other undesired behavior when the sanitized HTML is rendered in a browser [2]. The fix introduces explicit warnings that Sanitize cannot fully sanitize ` and ` contents and updates the relaxed config to remove these elements from allowlisting [3][4].

The vulnerability is fixed in Sanitize version 5.2.1. Users are advised to upgrade immediately. Workarounds are not recommended, as the core issue is architectural within the HTML parsing approach [2][3].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
sanitizeRubyGems
>= 3.0.0, < 5.2.15.2.1

Affected products

2
  • ghsa-coords
    Range: >= 3.0.0, < 5.2.1
  • rgrove/Sanitizev5
    Range: >= 3.0.0, < 5.2.1

Patches

1
a11498de9e28

Fix sanitization bypass in HTML foreign content

https://github.com/rgrove/sanitizeRyan GroveJun 15, 2020via ghsa
4 files changed · +45 11
  • lib/sanitize/config/default.rb+1 1 modified
    @@ -74,7 +74,7 @@ module Config
           # the specified elements (when filtered) will be removed, and the contents
           # of all other filtered elements will be left behind.
           :remove_contents => %w[
    -        iframe noembed noframes noscript script style
    +        iframe math noembed noframes noscript plaintext script style svg xmp
           ],
     
           # Transformers allow you to filter or alter nodes using custom logic. See
    
  • README.md+11 0 modified
    @@ -72,6 +72,11 @@ Sanitize can sanitize the following types of input:
     * Standalone CSS stylesheets
     * Standalone CSS properties
     
    +However, please note that Sanitize _cannot_ fully sanitize the contents of
    +`<math>` or `<svg>` elements, since these elements don't follow the same parsing
    +rules as the rest of HTML. If this is something you need, you may want to look
    +for another solution.
    +
     ### HTML Fragments
     
     A fragment is a snippet of HTML that doesn't contain a root-level `<html>`
    @@ -415,6 +420,12 @@ elements not in this array will be removed.
     ]
     ```
     
    +**Warning:** Sanitize cannot fully sanitize the contents of `<math>` or `<svg>`
    +elements, since these elements don't follow the same parsing rules as the rest
    +of HTML. If you add `math` or `svg` to the allowlist, you must assume that any
    +content inside them will be allowed, even if that content would otherwise be
    +removed by Sanitize.
    +
     #### :parser_options (Hash)
     
     [Parsing options](https://github.com/rubys/nokogumbo/tree/v2.0.1#parsing-options) supplied to `nokogumbo`.
    
  • test/test_clean_element.rb+20 10 modified
    @@ -192,21 +192,16 @@
             .must_equal ''
         end
     
    -    it 'should escape the content of removed `plaintext` elements' do
    -      Sanitize.fragment('<plaintext>hello! <script>alert(0)</script>')
    -        .must_equal 'hello! &lt;script&gt;alert(0)&lt;/script&gt;'
    -    end
    -
    -    it 'should escape the content of removed `xmp` elements' do
    -      Sanitize.fragment('<xmp>hello! <script>alert(0)</script></xmp>')
    -        .must_equal 'hello! &lt;script&gt;alert(0)&lt;/script&gt;'
    -    end
    -
         it 'should not preserve the content of removed `iframe` elements' do
           Sanitize.fragment('<iframe>hello! <script>alert(0)</script></iframe>')
             .must_equal ''
         end
     
    +    it 'should not preserve the content of removed `math` elements' do
    +      Sanitize.fragment('<math>hello! <script>alert(0)</script></math>')
    +        .must_equal ''
    +    end
    +
         it 'should not preserve the content of removed `noembed` elements' do
           Sanitize.fragment('<noembed>hello! <script>alert(0)</script></noembed>')
             .must_equal ''
    @@ -222,6 +217,11 @@
             .must_equal ''
         end
     
    +    it 'should not preserve the content of removed `plaintext` elements' do
    +      Sanitize.fragment('<plaintext>hello! <script>alert(0)</script>')
    +        .must_equal ''
    +    end
    +
         it 'should not preserve the content of removed `script` elements' do
           Sanitize.fragment('<script>hello! <script>alert(0)</script></script>')
             .must_equal ''
    @@ -232,6 +232,16 @@
             .must_equal ''
         end
     
    +    it 'should not preserve the content of removed `svg` elements' do
    +      Sanitize.fragment('<svg>hello! <script>alert(0)</script></svg>')
    +        .must_equal ''
    +    end
    +
    +    it 'should not preserve the content of removed `xmp` elements' do
    +      Sanitize.fragment('<xmp>hello! <script>alert(0)</script></xmp>')
    +        .must_equal ''
    +    end
    +
         strings.each do |name, data|
           it "should clean #{name} HTML" do
             Sanitize.fragment(data[:html]).must_equal(data[:default])
    
  • test/test_malicious_html.rb+13 0 modified
    @@ -219,4 +219,17 @@
           end
         end
       end
    +
    +  # https://github.com/rgrove/sanitize/security/advisories/GHSA-p4x4-rw2p-8j8m
    +  describe 'foreign content bypass in relaxed config' do
    +    it 'prevents a sanitization bypass via carefully crafted foreign content' do
    +      %w[iframe noembed noframes noscript plaintext script style xmp].each do |tag_name|
    +        @s.fragment(%[<math><#{tag_name}>/*&lt;/#{tag_name}&gt;&lt;img src onerror=alert(1)>*/]).
    +          must_equal ''
    +
    +        @s.fragment(%[<svg><#{tag_name}>/*&lt;/#{tag_name}&gt;&lt;img src onerror=alert(1)>*/]).
    +          must_equal ''
    +      end
    +    end
    +  end
     end
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

9

News mentions

0

No linked articles in our index yet.