Repository navigation
XSS in html.parser library #102555
Copy link
Copy link
Closed
Labels
stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-securityA security issueA security issue
Description
Description
The library html.parser allows an attacker to bypass any whitelist of HTML tags and attributes that seek to mitigate XSS. This is possible because the application does not correctly parse the HTML comments in the user input.
Vulnerability
This vulnerability occurs because the application does not correctly parse the HTML comments in the user input.
Exploitation
In this scenario a developer parses the HTML entered by the user to validate it with an allowlist of tags and attributes. This is to prevent XSS attacks. In this case we see how we can bypass a security check of this type, thanks to the fact that the parser does not parse the HTML comments properly.
poc.py
from html.parser import HTMLParser
from html.entities import name2codepoint
class MyHTMLParser(HTMLParser):
def handle_starttag(self, tag, attrs):
print("Start tag:", tag)
# Whitelist Tags
print("Invalid tag:",tag != "h1")
for attr in attrs:
# Whitelist Attr
print("attr:", attr)
print("Invalid attr:",attr != "alt")
def handle_endtag(self, tag):
print("End tag :", tag)
def handle_data(self, data):
print("Data :", data)
def handle_comment(self, data):
print("Comment :", data)
def handle_entityref(self, name):
c = chr(name2codepoint[name])
print("Named ent:", c)
def handle_charref(self, name):
if name.startswith('x'):
c = chr(int(name[1:], 16))
else:
c = chr(int(name))
print("Num ent :", c)
def handle_decl(self, data):
print("Decl :", data)
parser = MyHTMLParser()
parser.feed('<!--!> <h1 value="--!><script>alert(document.domain)</script>')
# HTML is safe, we can proceedEvidence of exploitation
Expected behavior
System Information
- CPython versions tested on: Python 3.10.8
- Operating system and architecture: GNU/Linux x86_64
Linked PRs
- gh-102555 Increase HTML standard compliance for closing comment tags #117406
- gh-102555: Fix comment parsing in HTMLParser #135664
- [3.14] gh-102555: Fix comment parsing in HTMLParser according to the HTML5 standard (GH-135664) #136271
- [3.13] gh-102555: Fix comment parsing in HTMLParser according to the HTML5 standard (GH-135664) #136272
- [3.12] gh-102555: Fix comment parsing in HTMLParser according to the HTML5 standard (GH-135664) #136273
- [3.11] gh-102555: Fix comment parsing in HTMLParser according to the HTML5 standard (GH-135664) #136274
- [3.10] gh-102555: Fix comment parsing in HTMLParser according to the HTML5 standard (GH-135664) #136275
- [3.9] gh-102555: Fix comment parsing in HTMLParser according to the HTML5 standard (GH-135664) #136276
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-securityA security issueA security issue
Projects
- StatusShow more project fieldsDone


Activity
Retr02332 commentedon Mar 9, 2023
@gpshead
Retr02332 commentedon Mar 9, 2023
@pochmann Open that HTML in the browser. Then you will see that the script is executed.
So the parser does not detect the script tag here, so if a developer uses this library to parse a user's HTML to later scan against XSS for example, an attacker would end up bypassing the protections in this case.
Retr02332 commentedon Mar 9, 2023
@pochmann Not exactly: https://www.youtube.com/watch?v=H1TVk3HhL9E
The parser must parse the user input well. The golang net/html package validates well the input I put in this issue for example.
gpshead commentedon Mar 9, 2023
Background: This was reported to the PSRT first, we suggested it was better to file as a public issue and work on it here. Thanks for reporting and filing.
Note that animated GIFs or Videos are not a meaningful way to report software bugs. They are a major accessibility problem as they contain no text and thus cannot be used for anything. This is software, software is text. Please just create code and data snippets and check them in to a branch somewhere or post them as Gists if they cannot simply be included in a bug filing itself.
What's missing in this bug as written is explicit actual behavior and expected behavior of the code sample on the example document.
gpshead commentedon Mar 9, 2023
There are better html parsing libraries for Python than
html.parserfrom the stdlib. Using BeautifulSoup akabs4to explore some of them, we can see that even when it uses html.parser it is able to make sense of the example document. But that other parsers such aslxmlandhtml5libdo a much better job:The latter two product similar output to what you'll see in an actual web browsers DOM for this document and are thus what I'd suggest people actually use.
I'm not sure how
bs4coaxedhtml.parserto get the script tag out vs using thehtml.parser.HTMLParsercallback API as the POC example code does. Regardless, kudos tobs4which is the library I recommend everyone use for serious html needs.Those looking into
html.parserfor this issue should try to understand how it'sHTMLParseris supposed to work and vs what is really does in the face of an HTML Comment as defined in https://html.spec.whatwg.org/#comments. (and realize thathtml.parsercode was likely written long before WHATWG even existed)Hitachi-Pika commentedon Apr 6, 2023
1. I tested with only stattag
<div>:>>> parser.feed('<div> this is div content ')Result:
Start tag: divData: this is div content2. But when I test with
<style>or<script>tag I can't get the data>>> parser.feed('<script> this is div content ')Result:
Start tag: scriptI wonder if this is a problem?
Privat33r-dev commentedon Mar 31, 2024
As we can see there (comment was added by me for clarity), the parser do not recognize closing comment tag.
According to whatwg
Pay attention to 3. "POC" uses
--!>instead of proper-->, but browsers are more lenient due to the recommendation that I found in a comment of the GNOME's libxml2 that lxml potentially uses.However,
htmlParseErris invoked in the libxml2 on the incorrect comment closing tag.My recommendation based on my findings: change
Lib\_markupbase.py:12 line from_commentclose = re.compile(r'--\s*>')to_commentclose = re.compile(r'--!?>')and potentially add some output in case if the!sign is met in a closing tag.ezio-melotti commentedon Apr 1, 2024
FWIW a few years ago I updated it to handle HTML5 according to the specs, even though it's not 100% compliant (especially with some corner cases and invalid markup).
html.parsershould follow the specs whenever possible and ideally behave like browsers do, without ever raising errors for invalid markup.Add html closing comment tags test cases
serhiy-storchaka commentedon May 7, 2025
If I understand correctly, the problem is that "
--!>" is not recognized as the end of the comment.This is indeed a bug. The parser should switch to the comment end bang state after "
--!" and then to the data state after "--!>" (this is an incorrectly-closed-comment parse error, but it should be tolerated). See https://html.spec.whatwg.org/multipage/parsing.html#comment-end-state.There are also other states which lead to the abrupt end of the comment. For example, "
<!-->".10 remaining items
[3.13] gh-102555: Fix comment parsing in HTMLParser according to the …
[3.14] gh-102555: Fix comment parsing in HTMLParser according to the …
pythongh-102555: Fix comment parsing in HTMLParser according to the H…
[3.9] gh-102555: Fix comment parsing in HTMLParser according to the H…
[3.10] gh-102555: Fix comment parsing in HTMLParser according to the …
[3.11] gh-102555: Fix comment parsing in HTMLParser according to the …
[3.12] gh-102555: Fix comment parsing in HTMLParser according to the …
pythongh-102555: Fix comment parsing in HTMLParser according to the H…
pythongh-102555: Fix comment parsing in HTMLParser according to the H…
[3.9] pythongh-102555: Fix comment parsing in HTMLParser according to…
pythongh-102555: Fix comment parsing in HTMLParser according to the H…
pythongh-102555: Fix comment parsing in HTMLParser according to the H…