python-websockets / python-websockets/websockets

Proxy credentials in the proxy URL are not percent-decoded

Open Beginner friendly
#1,761 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Python
Stars
5.7k
Forks
613
Avg merge
23h 5m
Merged PRs (30d)
9

Description

Description

parse_proxy() takes username and password from urllib.parse.urlparse(...) as they are, without percent-decoding them. A password that contains a reserved character has to be percent-encoded to be representable in the URL at all (socks5://alice:p%40ss@host:1080 for the password p@ss), but websockets then sends the literal string p%40ss to the proxy: connect_socks_proxy() hands proxy.username / proxy.password to python-socks unchanged, and connect_http_proxy() base64-encodes them unchanged for Proxy-Authorization.

python-socks itself (python_socks._helpers.parse_proxy_url) applies unquote() to both, so the same URL works with python-socks directly and with other clients that build on it, but not through websockets' proxy= parameter. RFC 3986 section 3.2.1 defines userinfo as percent-encoded.

Reproduction
>>> from websockets.proxy import parse_proxy
>>> p = parse_proxy("socks5://alice:p%40ss@127.0.0.1:1080")
>>> p.password
'p%40ss'

Against a SOCKS5 proxy with user/password auth the connection is rejected (ProxyError: failed to connect to SOCKS proxy), against an HTTP CONNECT proxy with basic auth it is answered with 407.

Environment

websockets 16.0, Python 3.13.5, python-socks 3.1.1, Linux x86_64.

Expected

parse_proxy() percent-decodes username and password (e.g. urllib.parse.unquote), like python-socks and requests do for proxy URLs, so that credentials with @, :, / or % can be used.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the parse_proxy() entry point in websockets.proxy and trace how its credentials reach connect_socks_proxy() and connect_http_proxy(). Verify the reproduction URL with a percent-encoded password, then confirm that both proxy paths receive decoded username and password values and that the existing proxy tests pass.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
networking
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
74/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.