Repository navigation
urlparse does not correctly handle signs, underscores, and whitespace in port numbers #96035
Description
Activity
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Aug 16, 2022 Similarly we accept
urlparse("http://python.org:10_000").port.Do you think this has any practical effect, for example on security? Most likely we'll have to go through a deprecation cycle to remove the noncompliant behavior.
Reacted by Ben KallusWe also accept
urlparse("http://python.org:\r\n80\r\n").port, becauseinttrims whitespace.I think it's plausible that there are security concerns stemming from desyncing a front-end server using urlparse from a backend server using something else. I can imagine, for instance, another implementation of a permissive URL parser interpreting "http://python.org:80_80" as having port 80, leading to disagreement between the servers as to port in question. I could also see the use of whitespace in the port string (especially
"\r\n") as a potential source of confusion for HTTP servers, because even though urlparse has no problem with"http://python.org:80\r\n", a CRLF ends the HTTP 1.1 start line and would lead to an invalid HTTP message. I'm missing the creativity right now to string all of this together into something tangible, but I feel like it could be done.Reacted by Jelle Zijlstra- changed the title
[-]urlparse does not correctly handle signs in port numbers[/-][+]urlparse does not correctly handle signs, underscores, and whitespace in port numbers[/+]on Aug 16, 2022 I just ran into this issue with whitespace. It didn't cause a security issue, but rather a bunch of unexpected errors:
>>> urlparse(' https://example.com ') ParseResult(scheme='', netloc='', path=' https://example.com ', params='', query='', fragment='')I just ran into this issue with whitespace. It didn't cause a security issue, but rather a bunch of unexpected errors:
>>> urlparse(' https://example.com ') ParseResult(scheme='', netloc='', path=' https://example.com ', params='', query='', fragment='')This is definitely weird behavior, but maybe not a bug. RFC3986 says a URI
schememust begin with anALPHA, so I think we're right in determining that there is no scheme (even though the RFC says there must be a scheme, I think the WHATWG spec says you can omit it in some situations. It's unclear to me.) The WHATWG spec also says that any ASCII string is a valid URL path, which is also in disagreement with the RFC. If we're going with the WHATWG interpretation, then' https://example.com 'is a perfectly valid URL path and nothing has been parsed incorrectly. If we're going with the RFC, thenurlparse's behavior is not good.Another similar bug:
>>> urlparse("https:// example.com ") ParseResult(scheme='https', netloc=' example.com ', path='', params='', query='', fragment='')
This time, putting space after the
://leads to spaces in the hostname. That's also wrong according to RFC, and okay according to WHATWG.Hmmm... interesting, what about the case without a scheme with port?
>>> urlparse('www.example.com:80') ParseResult(scheme='www.example.com', netloc='', path='80', params='', query='', fragment='')Reacted by Ben KallusHmmm... interesting, what about the case without a scheme with port?
>>> urlparse('www.example.com:80') ParseResult(scheme='www.example.com', netloc='', path='80', params='', query='', fragment='')This is just objectively wrong, and should probably be its own bug report. Good find.
Most likely we'll have to go through a deprecation cycle to remove the noncompliant behavior.
I don't think so. This is clearly a bug, not a feature someone should depend on.
- added3.11only security fixesonly security fixes3.10 (EOL)end of lifeend of life3.12only security fixesonly security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytriagedThe issue has been accepted as valid by a triager.The issue has been accepted as valid by a triager.
on Sep 13, 2022 All the backports are merged, thanks for reporting and fixing this issue!
Background
RFC 3986 (spec for URIs) defines a valid port string with the following grammar rule:
port = *DIGITHere's the WHATWG URL spec definition:
"""
A URL-port string must be one of the following:
"""1
The bug
This is the port string parsing code from
Lib/urllib/parse.py:166-176:This will erroneously validate strings
"-0"andf"+{x}"for any value ofxin the valid range. Given that+and-are not digits, this behavior is in violation of both specifications.This bug is easily reproducible with the following snippet:
Happy to submit a PR, but don't want to step on any toes over at #25774.
My environment
Footnotes
Given that this is
urlparseand noturiparse, it seems appropriate that we do not accept port numbers outsiderange(2**16), even though such numbers are allowed by RFC 3986. ↩