What changed in urllib3 from 1 to 2
9 releases numbered after 1.26.20 up to and including 2.7.0, stable releases only. 1.26.20 and 2.7.0 are the newest stable releases of 1 and 2 we track; this page follows them as new ones ship.
- 5 CVEs mentioned
- 3 remove or deprecate something
56 changes across 9 releases
- Restore previously removed HTTPResponse.getheaders() and HTTPResponse.getheader() methods
- Enable retrieval, deletion, and membership testing in HTTPHeaderDict using bytes keys
- Add host and port information to string representations of HTTPConnection
- Add support for Python 3.14 free-threading builds explicitly
- Added support for the compression.zstd module that is new in Python 3.14
- Added support for version 0.5 of hatch-vcs
- Added verify_flags option to create_urllib3_context with a default of VERIFY_X509_PARTIAL_CHAIN and VERIFY_X509_STRICT for Python 3.13+
- Added HTTPResponse.shutdown() to stop any ongoing or future reads for a specific response by calling shutdown(SHUT_RD) on the underlying socket
- Added support for JavaScript Promise Integration on Emscripten to enable more efficient WebAssembly requests and streaming
- Added the proxy_is_tunneling property to HTTPConnection and HTTPSConnection
- Added pickling support to NewConnectionError and NameResolutionError
- Added support for Python 3.13
- Added a probing mechanism for determining whether a given target origin supports HTTP/2 via ALPN
- Added support for sending a request body with HTTP/2
- Used FutureWarning instead of DeprecationWarning for better visibility of deprecation notices
- Bumped minimum supported pyOpenSSL version to 19.0.0
- Treat Retry-After times greater than 6 hours as 6 hours by default
- Change the zstd extra to install backports.zstd instead of zstandard on Python 3.13 and before
- Improve the performance of content decoding by optimizing BytesQueueBuffer class
- Updated exceptions to save and restore more properties during the pickle/serialization process
- Applied PEP 639 by specifying the license fields in pyproject.toml
- Excluded Transfer-Encoding: chunked from HTTP/2 request body
- Added version checking for h2 usage, now only accepting supported h2 major version 4.x.x
- Fixed HTTPResponse.read(amt=None) ignoring decompressed data buffered from previous partial reads
- Fixed HTTPResponse.read() caching only part of response after partial read when cache_content=True
- Fixed HTTPResponse.stream() and HTTPResponse.read_chunked() to handle amt=0
- Updated _TYPE_BODY type alias to include missing Iterable[str] for chunked request bodies
- Fixed LocationParseError when paths resembling schemeless URIs were passed to HTTPConnectionPool.urlopen()
- Fixed BaseHTTPResponse.readinto() type annotation to accept memoryview in addition to bytearray
- Fixed urllib3.connection.VerifiedHTTPSConnection on Emscripten
- HTTPResponse.read_chunked() now properly handles leftover data in the decoder's buffer when reading compressed chunked responses
- Fix redirect handling in urllib3.PoolManager when an integer is passed for the retries parameter
- Fix HTTPConnectionPool when used in Emscripten with no explicit port
- Fix handling of SSLKEYLOGFILE with expandable variables
- Raised exception for HTTPResponse.shutdown on a connection already released to the pool
- Fixed incorrect CONNECT statement when using an IPv6 proxy with connection_from_host where it would not be wrapped in []
- Fixed a bug with partial reads of streaming data in Emscripten
- Fixed debug logs rendering HTTP version as "HTTP/11" instead of "HTTP/1.1"
- Fixed the default encoding of chunked request bodies to be UTF-8 instead of ISO-8859-1
- Fixed ResourceWarning on CONNECT with Python < 3.11.4 by backporting CPython fix
- Adjusted tolerance for floating-point comparison on Windows to avoid flakiness in CI
- Fixed a crash where certain standard library hash functions were absent in restricted environments
- Fixed mypy error when adding to HTTPConnection.default_socket_options
- Removed support for end-of-life Python 3.9
- Removed support for end-of-life PyPy3.10
- Remove the HTTPResponse.getheaders() method in favor of HTTPResponse.headers
- Remove the HTTPResponse.getheader(name, default) method in favor of HTTPResponse.headers.get(name, default)
- Removed support for Python 3.8
- Fixed decompression-bomb safeguards bypass when HTTPResponse.drain_conn() was called after partial decompression
- Fixed decompression-bomb safeguards bypass during second HTTPResponse.read(amt=N) or HTTPResponse.stream(amt=N) call with Brotli decompression
- Fixed HTTP pools created using ProxyManager.connection_from_url to strip sensitive headers specified in Retry.remove_headers_on_redirect when redirecting to a different host
- Fixed a security issue where decompression-bomb safeguards of the streaming API were bypassed when HTTP redirects were followed (CVE-2026-21441, GHSA-38jv-5279-wg99)
- Fixed a security issue where streaming API could improperly handle highly compressed HTTP content leading to excessive resource consumption even when a small amount of data was requested (CVE-2025-66471)
- Fixed a security issue where an attacker could compose an HTTP response with virtually unlimited links in the Content-Encoding header, potentially leading to denial of service by exhausting system resources during decoding, limiting the number of allowed chained encodings to 5 (CVE-2025-66418)
- Pool managers now properly control redirects when retries is passed
- Redirects are now controlled by urllib3 in the Node.js runtime
Original release notes, newest first
The list above is our reading of these notes; the originals from urllib3 are here, one fold per release.
2.7.0
🚀 urllib3 is fundraising for HTTP/2 support
urllib3 is raising ~$40,000 USD to release HTTP/2 support and ensure long-term sustainable maintenance of the project after a sharp decline in financial support. If your company or organization uses Python and would benefit from HTTP/2 support in Requests, pip, cloud SDKs, and thousands of other projects please consider contributing financially to ensure HTTP/2 support is developed sustainably and maintained for the long-haul.
Thank you for your support.
Security
Addressed high-severity security issues. Impact was limited to specific use cases detailed in the accompanying advisories; overall user exposure was estimated to be marginal.
-
Decompression-bomb safeguards of the streaming API were bypassed:
- When
HTTPResponse.drain_conn()was called after the response had been read and decompressed partially. (Reported by @Cycloctane) - During the second
HTTPResponse.read(amt=N)orHTTPResponse.stream(amt=N)call when the response was decompressed using the official Brotli library. (Reported by @kimkou2024)
See GHSA-mf9v-mfxr-j63j for details.
- When
-
HTTP pools created using
ProxyManager.connection_from_urldid not strip sensitive headers specified inRetry.remove_headers_on_redirectwhen redirecting to a different host. (GHSA-qccp-gfcp-xxvc reported by @christos-spearbit)
Deprecations and Removals
- Used
FutureWarninginstead ofDeprecationWarningfor better visibility of existing deprecation notices. Rescheduled the removal of deprecated features to version 3.0. (https://github.com/urllib3/urllib3/issues/3763) - Removed support for end-of-life Python 3.9. (https://github.com/urllib3/urllib3/issues/3720)
- Removed support for end-of-life PyPy3.10. (https://github.com/urllib3/urllib3/issues/4979)
- Bumped the minimum supported pyOpenSSL version to 19.0.0. (https://github.com/urllib3/urllib3/issues/3777)
Bugfixes
- Fixed a bug where
HTTPResponse.read(amt=None)was ignoring decompressed data buffered from previous partial reads. (https://github.com/urllib3/urllib3/issues/3636) - Fixed a bug where
HTTPResponse.read()could cache only part of the response after a partial read whencache_content=True. (https://github.com/urllib3/urllib3/issues/4967) - Fixed
HTTPResponse.stream()andHTTPResponse.read_chunked()to handleamt=0. (https://github.com/urllib3/urllib3/issues/3793) - Updated
_TYPE_BODYtype alias to include missingIterable[str], matching the documented and runtime behavior of chunked request bodies. (https://github.com/urllib3/urllib3/issues/3798) - Fixed
LocationParseErrorwhen paths resembling schemeless URIs were passed toHTTPConnectionPool.urlopen(). (https://github.com/urllib3/urllib3/issues/3352) - Fixed
BaseHTTPResponse.readinto()type annotation to acceptmemoryviewin addition tobytearray, matching theio.RawIOBase.readintocontract and enabling use withio.BufferedReaderwithout type errors. (https://github.com/urllib3/urllib3/issues/3764)
2.6.3
🚀 urllib3 is fundraising for HTTP/2 support
urllib3 is raising ~$40,000 USD to release HTTP/2 support and ensure long-term sustainable maintenance of the project after a sharp decline in financial support. If your company or organization uses Python and would benefit from HTTP/2 support in Requests, pip, cloud SDKs, and thousands of other projects please consider contributing financially to ensure HTTP/2 support is developed sustainably and maintained for the long-haul.
Thank you for your support.
Changes
- Fixed a security issue where decompression-bomb safeguards of the streaming API were bypassed when HTTP redirects were followed. (CVE-2026-21441 reported by @D47A, 8.9 High, GHSA-38jv-5279-wg99)
- Started treating
Retry-Aftertimes greater than 6 hours as 6 hours by default. (https://github.com/urllib3/urllib3/issues/3743) - Fixed
urllib3.connection.VerifiedHTTPSConnectionon Emscripten. (https://github.com/urllib3/urllib3/issues/3752)
2.6.2
🚀 urllib3 is fundraising for HTTP/2 support
urllib3 is raising ~$40,000 USD to release HTTP/2 support and ensure long-term sustainable maintenance of the project after a sharp decline in financial support. If your company or organization uses Python and would benefit from HTTP/2 support in Requests, pip, cloud SDKs, and thousands of other projects please consider contributing financially to ensure HTTP/2 support is developed sustainably and maintained for the long-haul.
Thank you for your support.
Changes
- Fixed
HTTPResponse.read_chunked()to properly handle leftover data in the decoder's buffer when reading compressed chunked responses. (https://github.com/urllib3/urllib3/issues/3734)
2.6.1
🚀 urllib3 is fundraising for HTTP/2 support
urllib3 is raising ~$40,000 USD to release HTTP/2 support and ensure long-term sustainable maintenance of the project after a sharp decline in financial support. If your company or organization uses Python and would benefit from HTTP/2 support in Requests, pip, cloud SDKs, and thousands of other projects please consider contributing financially to ensure HTTP/2 support is developed sustainably and maintained for the long-haul.
Thank you for your support.
Changes
- Restore previously removed
HTTPResponse.getheaders()andHTTPResponse.getheader()methods. (#3731)
2.6.0
🚀 urllib3 is fundraising for HTTP/2 support
urllib3 is raising ~$40,000 USD to release HTTP/2 support and ensure long-term sustainable maintenance of the project after a sharp decline in financial support. If your company or organization uses Python and would benefit from HTTP/2 support in Requests, pip, cloud SDKs, and thousands of other projects please consider contributing financially to ensure HTTP/2 support is developed sustainably and maintained for the long-haul.
Thank you for your support.
Security
- Fixed a security issue where streaming API could improperly handle highly compressed HTTP content ("decompression bombs") leading to excessive resource consumption even when a small amount of data was requested. Reading small chunks of compressed data is safer and much more efficient now. (CVE-2025-66471 reported by @Cycloctane, 8.9 High, GHSA-2xpw-w6gg-jr37)
- Fixed a security issue where an attacker could compose an HTTP response with virtually unlimited links in the
Content-Encodingheader, potentially leading to a denial of service (DoS) attack by exhausting system resources during decoding. The number of allowed chained encodings is now limited to 5. (CVE-2025-66418 reported by @illia-v, 8.9 High, GHSA-gm62-xv2j-4w53)
[!IMPORTANT]
- If urllib3 is not installed with the optional
urllib3[brotli]extra, but your environment contains a Brotli/brotlicffi/brotlipy package anyway, make sure to upgrade it to at least Brotli 1.2.0 or brotlicffi 1.2.0.0 to benefit from the security fixes and avoid warnings. Prefer usingurllib3[brotli]to install a compatible Brotli package automatically.- If you use custom decompressors, please make sure to update them to respect the changed API of
urllib3.response.ContentDecoder.
Features
- Enabled retrieval, deletion, and membership testing in
HTTPHeaderDictusing bytes keys. (#3653) - Added host and port information to string representations of
HTTPConnection. (#3666) - Added support for Python 3.14 free-threading builds explicitly. (#3696)
Removals
- Removed the
HTTPResponse.getheaders()method in favor ofHTTPResponse.headers. Removed theHTTPResponse.getheader(name, default)method in favor ofHTTPResponse.headers.get(name, default). (#3622)
Bugfixes
- Fixed redirect handling in
urllib3.PoolManagerwhen an integer is passed for the retries parameter. (#3649) - Fixed
HTTPConnectionPoolwhen used in Emscripten with no explicit port. (#3664) - Fixed handling of
SSLKEYLOGFILEwith expandable variables. (#3700)
Misc
- Changed the
zstdextra to installbackports.zstdinstead ofzstandardon Python 3.13 and before. (#3693) - Improved the performance of content decoding by optimizing
BytesQueueBufferclass. (#3710) - Allowed building the urllib3 package with newer setuptools-scm v9.x. (#3652)
- Ensured successful urllib3 builds by setting Hatchling requirement to ≥ 1.27.0. (#3638)
2.5.0
🚀 urllib3 is fundraising for HTTP/2 support
urllib3 is raising ~$40,000 USD to release HTTP/2 support and ensure long-term sustainable maintenance of the project after a sharp decline in financial support. If your company or organization uses Python and would benefit from HTTP/2 support in Requests, pip, cloud SDKs, and thousands of other projects please consider contributing financially to ensure HTTP/2 support is developed sustainably and maintained for the long-haul.
Thank you for your support.
Security issues
urllib3 2.5.0 fixes two moderate security issues:
- Pool managers now properly control redirects when
retriesis passed — CVE-2025-50181 reported by @sandumjacob (5.3 Medium, GHSA-pq67-6m6q-mj2v) - Redirects are now controlled by urllib3 in the Node.js runtime — CVE-2025-50182 (5.3 Medium, GHSA-48p4-8xcf-vxj5)
Features
- Added support for the
compression.zstdmodule that is new in Python 3.14. See PEP 784 for more information. (#3610) - Added support for version 0.5 of
hatch-vcs(#3612)
Bugfixes
- Raised exception for
HTTPResponse.shutdownon a connection already released to the pool. (#3581) - Fixed incorrect
CONNECTstatement when using an IPv6 proxy withconnection_from_host. Previously would not be wrapped in[]. (#3615)
2.4.0
🚀 urllib3 is fundraising for HTTP/2 support
urllib3 is raising ~$40,000 USD to release HTTP/2 support and ensure long-term sustainable maintenance of the project after a sharp decline in financial support. If your company or organization uses Python and would benefit from HTTP/2 support in Requests, pip, cloud SDKs, and thousands of other projects please consider contributing financially to ensure HTTP/2 support is developed sustainably and maintained for the long-haul.
Thank you for your support.
Features
- Applied PEP 639 by specifying the license fields in pyproject.toml. (#3522)
- Updated exceptions to save and restore more properties during the pickle/serialization process. (#3567)
- Added
verify_flagsoption tocreate_urllib3_contextwith a default ofVERIFY_X509_PARTIAL_CHAINandVERIFY_X509_STRICTfor Python 3.13+. (#3571)
Bugfixes
- Fixed a bug with partial reads of streaming data in Emscripten. (#3555)
Misc
- Switched to uv for installing development dependecies. (#3550)
- Removed the
multiple.intoto.jsonlasset from GitHub releases. Attestation of release files since v2.3.0 can be found on PyPI. (#3566)
2.3.0
🚀 urllib3 is fundraising for HTTP/2 support
urllib3 is raising ~$40,000 USD to release HTTP/2 support and ensure long-term sustainable maintenance of the project after a sharp decline in financial support for 2023. If your company or organization uses Python and would benefit from HTTP/2 support in Requests, pip, cloud SDKs, and thousands of other projects please consider contributing financially to ensure HTTP/2 support is developed sustainably and maintained for the long-haul.
Thank you for your support.
Features
- Added
HTTPResponse.shutdown()to stop any ongoing or future reads for a specific response. It callsshutdown(SHUT_RD)on the underlying socket. This feature was sponsored by LaunchDarkly. (https://github.com/urllib3/urllib3/issues/2868) - Added support for JavaScript Promise Integration on Emscripten. This enables more efficient WebAssembly requests and streaming, and makes it possible to use in Node.js if you launch it as node
--experimental-wasm-stack-switching. (https://github.com/urllib3/urllib3/issues/3400) - Added the
proxy_is_tunnelingproperty toHTTPConnectionandHTTPSConnection. (https://github.com/urllib3/urllib3/issues/3285) - Added pickling support to
NewConnectionErrorandNameResolutionError. (https://github.com/urllib3/urllib3/issues/3480)
Bugfixes
- Fixed an issue in debug logs where the HTTP version was rendering as "HTTP/11" instead of "HTTP/1.1". (https://github.com/urllib3/urllib3/issues/3489)
Deprecations and Removals
- Removed support for Python 3.8. (https://github.com/urllib3/urllib3/issues/3492)
Full Changelog: https://github.com/urllib3/urllib3/compare/2.2.3...2.3.0
2.2.3
🚀 urllib3 is fundraising for HTTP/2 support
urllib3 is raising ~$40,000 USD to release HTTP/2 support and ensure long-term sustainable maintenance of the project after a sharp decline in financial support for 2023. If your company or organization uses Python and would benefit from HTTP/2 support in Requests, pip, cloud SDKs, and thousands of other projects please consider contributing financially to ensure HTTP/2 support is developed sustainably and maintained for the long-haul.
Thank you for your support.
Features
- Added support for Python 3.13. (#3473)
Bugfixes
- Fixed the default encoding of chunked request bodies to be UTF-8 instead of ISO-8859-1. All other methods of supplying a request body already use UTF-8 starting in urllib3 v2.0. (#3053)
- Fixed ResourceWarning on CONNECT with Python < 3.11.4 by backporting https://github.com/python/cpython/issues/103472. (`#3252)
- Adjust tolerance for floating-point comparison on Windows to avoid flakiness in CI (#3413)
- Fixed a crash where certain standard library hash functions were absent in restricted environments. (#3432)
- Fixed mypy error when adding to
HTTPConnection.default_socket_options. (#3448)
HTTP/2 (experimental)
HTTP/2 support is still in early development.
- Excluded Transfer-Encoding: chunked from HTTP/2 request body (#3425)
- Added version checking for
h2(https://pypi.org/project/h2/) usage. Now only accepting supported h2 major version 4.x.x. (#3290) - Added a probing mechanism for determining whether a given target origin supports HTTP/2 via ALPN. (#3301)
- Add support for sending a request body with HTTP/2 (#3302)
Full Changelog: https://github.com/urllib3/urllib3/compare/2.2.2...2.2.3