GHSA-qccp-gfcp-xxvc: Upgrade urllib3 to 2.7.0 and raise Python floor to 3.10 - #36
Draft
sgrammargs wants to merge 1 commit into
Draft
GHSA-qccp-gfcp-xxvc: Upgrade urllib3 to 2.7.0 and raise Python floor to 3.10#36sgrammargs wants to merge 1 commit into
sgrammargs wants to merge 1 commit into
Conversation
urllib3 2.2.3 is affected by seven advisories, six of which were flagged for this repo. The SDK is directly exposed: ynab/rest.py passes preload_content=False on every request (the streaming API targeted by the decompression-bomb issues) and builds ProxyManager/SOCKSProxyManager with auth headers (the proxied-redirect header leak). urllib3 2.7.0 is the first release fixing all of them, and it requires Python >= 3.10. Poetry cannot resolve it against python = "^3.8", so the floor moves to ^3.10. Python 3.8 (EOL Oct 2024) and 3.9 (EOL Oct 2025) are both past end-of-life. This is a breaking change for the published package and needs a major version bump before release; the version is left at 4.3.0 to match the convention of bumping separately. templates/pyproject.mustache is updated alongside pyproject.toml so the next SDK regeneration does not revert either constraint. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
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.
Why
Upgrades
urllib3from2.2.3to2.7.0, fixing the seven security advisories.PoolManagerinstantiationThis SDK is directly exposed — these are not theoretical transitive findings.
urllib3is a direct dependency andynab/rest.pyuses the exact affected surfaces:preload_content=Falseis passed on every request (rest.py:193,:202,:219,:230,:239,:256). All four decompression-bomb advisories target this path.urllib3.ProxyManagerandurllib3.contrib.socks.SOCKSProxyManagerare constructed withproxy_headers(rest.py:111,:115), andconfiguration.py:480builds auth headers viaurllib3.util.make_headers. That is the surface GHSA-qccp-gfcp-xxvc covers.configuration.retriesis passed straight into the pool manager (rest.py:91), so a consumer setting it reaches the CVE-2025-50181 path.Why 2.7.0 is safe
Reviewed
CHANGES.rstacross the entire 2.3.0 → 2.7.0 range, not just the target release. Two items needed a closer look, and neither affects this codebase:HTTPResponse.getheaders()/getheader()— this would have been a genuine break, but 2.6.1 restored both. Independently, the SDK'sRESTResponse.getheaders()/getheader()(rest.py:56-62) are its own wrappers that readself.response.headers/.headers.get()directly, so they never depended on the removed methods either way.urllib3.response.ContentDecoderAPI for custom decompressors, and warns that an ambient Brotli/brotlicffi install should be ≥ 1.2.0. This repo defines no custom decompressors, andpoetry.lockcontains nobrotli,brotlicffi, orzstandard— so neither caveat applies.Other behavior changes reviewed and judged benign: 2.6.3 caps
Retry-Afterat 6 hours (strictly safer); 2.7.0 switches deprecation notices fromDeprecationWarningtoFutureWarning(visibility only) and raises the minimum pyOpenSSL to 19.0.0 (not used here). The security fixes themselves only reject malformed or malicious input — well-formed requests are unaffected, which the before/after check below confirms.What changed
urllib3is already a direct dependency, so no constraints group or override was needed — the version was raised in[tool.poetry.dependencies]and applied with a scopedpoetry update urllib3rather than a barepoetry lock).The Python floor move is forced, not discretionary. urllib3 2.7.0 declares
requires_python >= 3.10, and Poetry refuses to resolve it against^3.8:Python 3.8 reached EOL in Oct 2024 and 3.9 in Oct 2025, so no still-supported version is dropped. Every urllib3 ≥ 2.3.0 requires ≥ 3.9, so any fix here required dropping 3.8 regardless of target.
pyproject.tomlpython = "^3.10",urllib3 = ">= 2.7.0, < 3.0.0"templates/pyproject.mustachepyproject.tomlis generated from this templatepoetry.lockurllib3 2.2.3 → 2.7.0.github/workflows/build-test.yml["3.8", "3.9", ...]→["3.10", "3.11", "3.12"].tool-versions3.9.10→3.10.20(the old pin was below the declared floor and isn't an installable-by-default version locally)requirements.txturllib3 >= 2.1.0→>= 2.7.0(this is whattox.iniinstalls from)README.mdNo cascade occurred, and I checked rather than assumed. The scoped update moves exactly one package:
The only other lockfile movement is marker bookkeeping with no version changes:
exceptiongroup's marker narrows frompython_version < "3.11"to== "3.10", andannotated-typesdrops atyping-extensionssub-dependency that only applied below 3.9 (now unreachable). Raising the floor permits newer releases of the other 31 packages but does not force them, so they stay pinned.mypy 1.14.1,pytest 8.3.5,coverage 7.6.1,pydantic 2.10.6,flake8 5.0.4,tox 4.25.0,virtualenv 20.29.3). Those become eligible to jump now, so a future barepoetry lockwill sweep them all forward at once. This PR deliberately does not.versionis left at4.3.0. Dropping Python support is semver-major and needs a 5.0.0 bump before release — kept separate to match the repo's existing "Bumping version for X" commit convention.Verified
Against this repo's pinned toolchain — Python 3.10.20 (installed to match the updated
.tool-versions) and Poetry 2.3.2 (matching the existing lock header, solock-version = "2.1"and the generator comment are preserved):Test suite: 162 passed — identical to the
mainbaseline. But this is weak evidence and should not be read as proof the upgrade works: the only test touchingrest.pymocks urllib3 out entirely (MagicMock()intests/test_response_deserialize.py), no test issues a real request, andrest.pysits at 40% coverage. Hence the functional check below.Reproduced two advisory PoCs against a local HTTP server, before and after. Ran the same script under 2.2.3 and 2.7.0 with the SDK importable in both:
RESTClientObject(incl.preload_content=False)sdk_get=True sdk_post=True status=200sdk_get=True sdk_post=True status=200(byte-identical)PoolManager(retries=False)vs a 302status=200→ redirect followed (vulnerable)status=302→ not followed (fixed)Content-Encoding: gziplinksb'payload'→ 7 links accepted (vulnerable)DecodeError→ chain rejected (fixed)Generated with Claude Code