Skip to content

Commit 4ea9483

Browse files
committed
Validate final URL after redirects in catalog fetch
urlopen follows redirects, so validate the response URL against the same HTTPS/localhost rules to prevent redirect-based downgrade attacks.
1 parent 88f9a36 commit 4ea9483

1 file changed

Lines changed: 13 additions & 9 deletions

File tree

src/specify_cli/workflows/catalog.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -319,21 +319,25 @@ def _fetch_single_catalog(
319319
except (json.JSONDecodeError, OSError):
320320
pass
321321

322-
# Fetch from URL — validate scheme before opening
322+
# Fetch from URL — validate scheme before opening and after redirects
323323
from urllib.parse import urlparse
324324
from urllib.request import urlopen
325325

326-
parsed = urlparse(entry.url)
327-
is_localhost = parsed.hostname in ("localhost", "127.0.0.1", "::1")
328-
if parsed.scheme != "https" and not (
329-
parsed.scheme == "http" and is_localhost
330-
):
331-
raise WorkflowCatalogError(
332-
f"Refusing to fetch catalog from non-HTTPS URL: {entry.url}"
333-
)
326+
def _validate_catalog_url(url: str) -> None:
327+
parsed = urlparse(url)
328+
is_localhost = parsed.hostname in ("localhost", "127.0.0.1", "::1")
329+
if parsed.scheme != "https" and not (
330+
parsed.scheme == "http" and is_localhost
331+
):
332+
raise WorkflowCatalogError(
333+
f"Refusing to fetch catalog from non-HTTPS URL: {url}"
334+
)
335+
336+
_validate_catalog_url(entry.url)
334337

335338
try:
336339
with urlopen(entry.url, timeout=30) as resp: # noqa: S310
340+
_validate_catalog_url(resp.geturl())
337341
data = json.loads(resp.read().decode("utf-8"))
338342
except Exception as exc:
339343
# Fall back to cache if available

0 commit comments

Comments
 (0)