Repository navigation
2.7.18.16: urllib2 HTTPPasswordMgr sends https credentials over http (CVE-2026-15806) - #102
Merged
Merged
Conversation
…-2026-15806) Backport of python/cpython pythongh-155694 (3.14 a0d023f) to 2.7.18.x. HTTPPasswordMgr (and HTTPPasswordMgrWithDefaultRealm) reduced URIs to (authority, path) and dropped the scheme, so credentials added for https://example.com/ were also returned for http://example.com/. An attacker who can redirect or downgrade a client to plain HTTP could then capture Basic/Digest credentials meant only for TLS. Stored and requested URIs now keep their scheme, and a stored URI with a scheme only matches requests with the same scheme. A stored bare authority ("example.com") or network-path reference ("//example.com/") still matches any scheme, as before; reduce_uri() and is_suburi() keep their public behavior. 2.7.18.x: 2.7 has no HTTPPasswordMgrWithPriorAuth, so only add_password()/find_user_password() change. (scheme,) + tuple replaces the 3.x star-unpacking. 2.7's password-manager tests are doctests, so the new tests go in a PasswordManagerSchemeTests class registered in test_main(), with an extra HTTPPasswordMgrWithDefaultRealm case. Co-Authored-By: Claude Opus 5.5 <[email protected]>
ezequielp-activestate
approved these changes
Oct 28, 2026
ezequielp-activestate
left a comment
There was a problem hiding this comment.
No blockers. The change is upstream's pythongh-155694 fix (a7bb524), minus the HTTPPasswordMgrWithPriorAuth part, since that class doesn't exist in 2.7. 2.7's urlparse.urlsplit lower-cases the scheme and returns no netloc for a bare host or host:port, so a bare authority still matches any scheme.
- Repro:
add_password("R", "https://example.com/", ...), thenfind_user_password("R", "http://example.com/"):- On the base, it returns the credentials, for both
HTTPPasswordMgrandHTTPPasswordMgrWithDefaultRealm. - On this branch, it returns
(None, None), andhttps://example.com/substill returns them. - A bare
example.comentry still matcheshttp://example.com/and the scheme-less authorityProxyBasicAuthHandlerpasses.
- On the base, it returns the credentials, for both
- Tests:
test_urllib2andtest_urllib2_localnetpass. The new tests fail against the baseurllib2.py.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backport of python/cpython pythongh-155694 (CVE-2026-15806, PSF-2026-36) to 2.7.18.x.
Problem:
urllib2.HTTPPasswordMgrandHTTPPasswordMgrWithDefaultRealmdropped the URL scheme when matching, so credentials stored forhttps://example.com/were also used forhttp://example.com/. Anyone who could downgrade or redirect the client to plain HTTP could capture credentials meant for TLS.Fix: a stored URI that includes a scheme now only matches requests with the same scheme. A stored bare authority (
example.com) or//host/reference still matches any scheme.reduce_uri()andis_suburi()behave as before.Behavior change: credentials stored for
https://…are no longer sent tohttp://…. This is the intended security fix, but code that relied on it needs to also add thehttp://URI or a bare authority.Tests:
PasswordManagerSchemeTests, which adds a default-realm case to upstream's tests.test_urllib2passes 52/52 and the existing doctests pass (66 + 11).test_urllib2_localnet,test_urllib2netandtest_xmlrpcpass.Part of 2.7.18.16. It targets the
2.7.18.16integration branch.