diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py index 7efbc81a16096a6..fd57cc83921c1b6 100644 --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -1735,6 +1735,27 @@ def test_proxy_basic_auth(self): "proxy.example.com:3128", ) + def test_proxy_basic_auth_ignores_direct_407(self): + # gh-158907: a direct HTTP origin that returns 407 must not receive + # credentials registered for the same authority over HTTPS. + opener = OpenerDirector() + opener.add_handler(urllib.request.ProxyHandler({})) + password_manager = urllib.request.HTTPPasswordMgr() + auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager) + realm = "test-realm" + http_handler = MockHTTPHandlerRedirect( + 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm) + opener.add_handler(auth_handler) + opener.add_handler(http_handler) + + password_manager.add_password( + realm, "https://example.com/", "victim-user", "victim-secret") + opener.open("http://example.com/resource") + + self.assertEqual(len(http_handler.requests), 1) + self.assertFalse( + http_handler.requests[0].has_header("Proxy-authorization")) + def test_basic_and_digest_auth_handlers(self): # HTTPDigestAuthHandler raised an exception if it couldn't handle a 40* # response (https://bugs.python.org/issue1479302), where it should instead diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index 59ed4a7140d59c6..83e1d6f51f76d46 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -1048,6 +1048,9 @@ class ProxyBasicAuthHandler(AbstractBasicAuthHandler, BaseHandler): auth_header = 'Proxy-authorization' def http_error_407(self, req, fp, code, msg, headers): + # gh-158907: a 407 from a direct origin is not a proxy challenge + if not req.has_proxy() and not req._tunnel_host: + return None # http_error_auth_reqed requires that there is no userinfo component in # authority. Assume there isn't one, since urllib.request does not (and # should not, RFC 3986 s. 3.2.1) support requests for URLs containing diff --git a/Misc/NEWS.d/next/Security/2026-10-07-13-30-00.gh-issue-158907.k4Qm2p.rst b/Misc/NEWS.d/next/Security/2026-10-07-13-30-00.gh-issue-158907.k4Qm2p.rst new file mode 100644 index 000000000000000..9b635298c3560ce --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-10-07-13-30-00.gh-issue-158907.k4Qm2p.rst @@ -0,0 +1,4 @@ +:class:`~urllib.request.ProxyBasicAuthHandler` no longer sends credentials +in response to ``407`` from a direct origin. A scheme-less lookup against +the origin host could match passwords stored for an HTTPS URL and retry +the cleartext request with ``Proxy-Authorization``.