Repository: mozilla/bleach

Issue:
bug: bleach truncates Katex style attributes
**Bleach truncates a lot of Katex style attributes**

Basic example: a markdown_katex output may contain a span like so : `<span class="vlist" style="height:1.0697em;">`. It contains a `style` attribute, and when passed through bleach (allowing the `style` attribute), I get this:

```
<span class="vlist" style=""></span>
```

While the desired output would be:

```
<span class="vlist" style="height:1.0697em;"></span>
```

As a result, actual Katex math doesn't render properly.

** python and bleach versions:**

 - Python Version: 3.9.2
 - Bleach Version: 5.0.1
 - Markdown-katex Version: 202112.1034

**To Reproduce**

Steps to reproduce the behavior:

```python
from bleach import Cleaner
 
cleaner = Cleaner(tags = ['span'],
                  attributes = {'span': ['class', 'style']})
          
minimal_katex_span = '<span class="vlist" style="height:1.0697em;">'
res = cleaner.clean(minimal_katex_span)
print(res)
```

**Additional context**

I am unsure if this is actually a bug or intended behavior in some way. The more general problem I face is: how to correctly use bleach after user input is transformed through markdown with the markdown_katex extension?


Comments:

Patch:
diff --git a/bleach/sanitizer.py b/bleach/sanitizer.py
index 6527ac0..da9637c 100644
--- a/bleach/sanitizer.py
+++ b/bleach/sanitizer.py
@@ -48,6 +48,10 @@ INVISIBLE_CHARACTERS_RE = re.compile("[" + INVISIBLE_CHARACTERS + "]", re.UNICOD
 INVISIBLE_REPLACEMENT_CHAR = "?"
 
 
+class NoCssSanitizerWarning(UserWarning):
+    pass
+
+
 class Cleaner:
     """Cleaner for cleaning HTML fragments of malicious content
 
@@ -143,6 +147,25 @@ class Cleaner:
             alphabetical_attributes=False,
         )
 
+        if css_sanitizer is None:
+            # FIXME(willkg): this doesn't handle when attributes or an
+            # attributes value is a callable
+            attributes_values = []
+            if isinstance(attributes, list):
+                attributes_values = attributes
+
+            elif isinstance(attributes, dict):
+                attributes_values = []
+                for values in attributes.values():
+                    if isinstance(values, (list, tuple)):
+                        attributes_values.extend(values)
+
+            if "style" in attributes_values:
+                warnings.warn(
+                    "'style' attribute specified, but css_sanitizer not set.",
+                    category=NoCssSanitizerWarning,
+                )
+
     def clean(self, text):
         """Cleans text and returns sanitized result as unicode
 
diff --git a/docs/clean.rst b/docs/clean.rst
index 7cfa757..9ebf74b 100644
--- a/docs/clean.rst
+++ b/docs/clean.rst
@@ -79,6 +79,12 @@ The default value is also a conservative dict found in
 ``bleach.sanitizer.ALLOWED_ATTRIBUTES``.
 
 
+.. Note::
+
+   If you allow ``style``, you need to also sanitize css. See
+   :ref:`clean-chapter-sanitizing-css` for details.
+
+
 .. autodata:: bleach.sanitizer.ALLOWED_ATTRIBUTES
 
 .. versionchanged:: 2.0
@@ -280,6 +286,8 @@ By default, Bleach will strip out HTML comments. To disable this behavior, set
    'my<!-- commented --> html'
 
 
+.. _clean-chapter-sanitizing-css:
+
 Sanitizing CSS
 ==============
 
diff --git a/setup.cfg b/setup.cfg
index aafdd5c..f631ecc 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -15,4 +15,6 @@ ignore =
 max-line-length = 88
 
 [tool:pytest]
-addopts = -W error:html5lib:DeprecationWarning
+filterwarnings =
+    error
+    ignore::bleach.sanitizer.NoCssSanitizerWarning


Test patch:
diff --git a/tests/test_clean.py b/tests/test_clean.py
index 4abe991..10a91fd 100644
--- a/tests/test_clean.py
+++ b/tests/test_clean.py
@@ -4,7 +4,7 @@ import pytest
 
 from bleach import clean
 from bleach.html5lib_shim import Filter
-from bleach.sanitizer import ALLOWED_PROTOCOLS, Cleaner
+from bleach.sanitizer import ALLOWED_PROTOCOLS, Cleaner, NoCssSanitizerWarning
 from bleach._vendor.html5lib.constants import rcdataElements
 
 
@@ -1176,6 +1176,20 @@ def test_preserves_attributes_order():
     assert cleaned_html == html
 
 
+@pytest.mark.parametrize(
+    "attr",
+    (
+        ["style"],
+        {"*": ["style"]},
+    ),
+)
+def test_css_sanitizer_warning(attr):
+    # If you have "style" in attributes, but don't set a css_sanitizer, it
+    # should raise a warning.
+    with pytest.warns(NoCssSanitizerWarning):
+        clean("foo", attributes=attr)
+
+
 class TestCleaner:
     def test_basics(self):
         TAGS = ["span", "br"]