Cross-Site Scripting (XSS) bugs are a headache, especially when they pop up in places you least expect, like your HTML sanitizer. CVE-2021-23980 is a mutation XSS that affects Bleach, a popular Python library used to clean HTML and prevent XSS attacks. But what makes this bug worrisome is how a rare combination of allowed HTML tags and a certain setting can break your sanitizer completely—even *with Bleach's filtering in place*.
Let’s break it down in simple terms, show you the actual problem, and walk through a code example so you don't ever get caught by this bug.
Also allow simple "innocent" tags like <p> or <br>
3. Add special tags like <style>, <title>, <noscript>, <script>, <noframes>, <iframe>, <xmp>, or <textarea> to the allowed tags
Call bleach.clean(..., strip_comments=False)
...then *mutation XSS* becomes possible! Even though none of these tags are allowed by default, if you hand-tweak Bleach and allow those tags, suddenly, crafted HTML can mutate your DOM and trigger a script.
⚠️ Short version: It’s not a problem if you stick with the defaults. But *if you use advanced/custom tag lists and switch off comment stripping*, you could be wide open.
Let’s See It In Code
Here’s a practical example that shows how enabling a particular cocktail of tags, and setting strip_comments=False, leads to XSS.
First, make sure you have Bleach installed
pip install bleach==3.3.
Now open a Python console
import bleach
# The deadly combo
ALLOWED_TAGS = [
'svg', 'p', 'style', # Just an example combo
]
# We turn off comment stripping
dirty_html = '''
<p>Normal paragraph</p>
<svg><p></svg>
<style>body{color:red}</style>
<!--
<script>alert("XSS")</script>
-->
'''
safe_html = bleach.clean(
dirty_html,
tags=ALLOWED_TAGS,
strip_comments=False
)
print(safe_html)
What happens here? In some browsers, the unclosed <svg><p></svg> can trigger a DOM parser quirk, causing browsers to reinterpret the structure. If a tag like <style>, <textarea>, <script>, or any of those, is allowed, this can even let an attacker execute JavaScript (for example, if script were allowed or an event handler snuck through).
> ⚡ *Mutation XSS* leverages browser parsing oddities—"mutating" the HTML structure after it's parsed and running attacker-controlled code.
How Attackers Exploit This
Attackers submit tricky HTML that—by using the right mix of allowed tags and parser quirks—confuses the browser to *escape* out of a svg or math context, then flip into a tag like <script> or <style> (which are treated specially by browsers). Even comments can play a role if they're preserved (i.e., if strip_comments=False). The upshot: XSS, even though you used a sanitizer.
If you allow the full dangerous set (['svg', 'p', 'style', 'script', ...]), an attacker might manage something like:
<svg><p><style><img src=x onerror=alert('XSS')</style>
With strip_comments=False, comments can also craftily confuse or hide mutating code.
You’re only vulnerable if
- Your bleach.clean() call allows *both* svg/math *and* p/br *and* any of the special tags
You set strip_comments=False
Normally, Bleach’s defaults keep you safe (strip_comments=True and none of the problematic tags are allowed). But if you *customize* the tag list for rich content, you might unwittingly open the door.
Bleach’s defaults block all of these.
2. Never set strip_comments=False unless you *know* you need HTML comments for some legitimate reason.
3. Upgrade Bleach to the latest version. The bug is fixed in later versions. See Bleach GHSA-w585-g5g6-wr6h and release notes.
References
- Mozilla Bleach Security Advisory: GHSA-w585-g5g6-wr6h
- CVE-2021-23980 in NVD
- Original Bleach Issue #505
- Mutation XSS by Mario Heiderich: How mutation XSS works (external link)
TL;DR
- CVE-2021-23980 is a mutation XSS that can allow scripts through Bleach if you get creative with the tags you allow and preserve HTML comments.
Timeline
Published on: 02/16/2023 22:15:00 UTC
Last modified on: 02/27/2023 15:19:00 UTC