Several call sites in xrspatial/geotiff/ route on startswith(('http://', 'https://')). That is case-sensitive, so HTTP://example.internal/... (uppercase) slips past _HTTPSource, skips the SSRF / DNS-pinning checks, and falls through to fsspec.
Fix: add a single _is_http_source(s) helper that does urlparse(s).scheme.lower() in ('http', 'https'), and route every call site through it.
Call sites to update (verify and replace all):
xrspatial/geotiff/_sources.py:1458, 1639
xrspatial/geotiff/_reader.py:145
xrspatial/geotiff/_writer.py:1244
xrspatial/geotiff/_backends/gpu.py:350, 1056
xrspatial/geotiff/_backends/dask.py:199
xrspatial/geotiff/_sidecar.py:46 (the existing _is_http_url helper is also case-sensitive)
Tests: uppercase HTTP:// routes through _HTTPSource; uppercase URLs targeting 127.0.0.1, 169.254.169.254, and localhost are still rejected by the SSRF check.
Acceptance: no security-relevant dispatch uses case-sensitive startswith. HTTP(S) SSRF protection applies regardless of scheme casing. Regression tests cover uppercase schemes and private-host rejection.
Parent: #2321 (sub-task 5).
Several call sites in
xrspatial/geotiff/route onstartswith(('http://', 'https://')). That is case-sensitive, soHTTP://example.internal/...(uppercase) slips past_HTTPSource, skips the SSRF / DNS-pinning checks, and falls through to fsspec.Fix: add a single
_is_http_source(s)helper that doesurlparse(s).scheme.lower() in ('http', 'https'), and route every call site through it.Call sites to update (verify and replace all):
xrspatial/geotiff/_sources.py:1458, 1639xrspatial/geotiff/_reader.py:145xrspatial/geotiff/_writer.py:1244xrspatial/geotiff/_backends/gpu.py:350, 1056xrspatial/geotiff/_backends/dask.py:199xrspatial/geotiff/_sidecar.py:46(the existing_is_http_urlhelper is also case-sensitive)Tests: uppercase
HTTP://routes through_HTTPSource; uppercase URLs targeting127.0.0.1,169.254.169.254, andlocalhostare still rejected by the SSRF check.Acceptance: no security-relevant dispatch uses case-sensitive
startswith. HTTP(S) SSRF protection applies regardless of scheme casing. Regression tests cover uppercase schemes and private-host rejection.Parent: #2321 (sub-task 5).