Summary
_HTTPSource in xrspatial/geotiff/_reader.py has two transport paths for HTTP range fetches: a urllib3 path and a stdlib urllib.request fallback. Only the urllib3 path pins the TCP connection to the IP returned by _validate_http_url, which is what closes the DNS-rebinding TOCTOU window from issue #1846. The stdlib fallback calls urllib.request.Request(self._url), which re-resolves the hostname at request time, so the IP the validator approved no longer guards the connection.
urllib3 is not listed under install_requires in setup.cfg. A production install that does not pull urllib3 in transitively will run the unpinned stdlib path and silently lose the #1846 mitigation.
Affected code
xrspatial/geotiff/_reader.py:1048, _HTTPSource.read_range stdlib fallback (urllib.request.Request(self._url, ...) via _get_stdlib_opener)
xrspatial/geotiff/_reader.py:1222, _HTTPSource.read_all stdlib fallback, same pattern
xrspatial/geotiff/_reader.py:344, _get_http_pool swallows ImportError and returns None, which routes callers into the stdlib fallback when urllib3 is missing
setup.cfg:21, install_requires does not list urllib3
Why it matters
_validate_http_url resolves the hostname and rejects addresses on loopback, link-local, or private space. Without IP pinning, a hostile resolver can return a public IP during validation and a private IP at connect time, and the check fails. Without urllib3 in install_requires, a real install never reaches the pinned path.
Proposed fix
- Add
urllib3 to install_requires in setup.cfg.
- Remove the stdlib fallback in
_HTTPSource.read_range and _HTTPSource.read_all.
- Simplify
_get_http_pool so it no longer catches ImportError.
- Delete
_get_stdlib_opener and _ValidatingRedirectHandler once nothing calls them.
- Drop the
test_stdlib_* cases in test_ssrf_hardening_1664.py. The test_urllib3_* cases in the same file already cover redirect re-validation for the path that remains.
Scope
Finding 1 only.
Summary
_HTTPSourceinxrspatial/geotiff/_reader.pyhas two transport paths for HTTP range fetches: a urllib3 path and a stdliburllib.requestfallback. Only the urllib3 path pins the TCP connection to the IP returned by_validate_http_url, which is what closes the DNS-rebinding TOCTOU window from issue #1846. The stdlib fallback callsurllib.request.Request(self._url), which re-resolves the hostname at request time, so the IP the validator approved no longer guards the connection.urllib3is not listed underinstall_requiresinsetup.cfg. A production install that does not pull urllib3 in transitively will run the unpinned stdlib path and silently lose the #1846 mitigation.Affected code
xrspatial/geotiff/_reader.py:1048,_HTTPSource.read_rangestdlib fallback (urllib.request.Request(self._url, ...)via_get_stdlib_opener)xrspatial/geotiff/_reader.py:1222,_HTTPSource.read_allstdlib fallback, same patternxrspatial/geotiff/_reader.py:344,_get_http_poolswallowsImportErrorand returnsNone, which routes callers into the stdlib fallback when urllib3 is missingsetup.cfg:21,install_requiresdoes not listurllib3Why it matters
_validate_http_urlresolves the hostname and rejects addresses on loopback, link-local, or private space. Without IP pinning, a hostile resolver can return a public IP during validation and a private IP at connect time, and the check fails. Without urllib3 ininstall_requires, a real install never reaches the pinned path.Proposed fix
urllib3toinstall_requiresinsetup.cfg._HTTPSource.read_rangeand_HTTPSource.read_all._get_http_poolso it no longer catchesImportError._get_stdlib_openerand_ValidatingRedirectHandleronce nothing calls them.test_stdlib_*cases intest_ssrf_hardening_1664.py. Thetest_urllib3_*cases in the same file already cover redirect re-validation for the path that remains.Scope
Finding 1 only.