security: fix SSRF via redirect bypass in ontology URL fetcher (CWE-918)

This commit is contained in:
Sunil
2026-08-10 21:52:47 +05:30
parent c85df419ae
commit 30d5fef180
+29 -16
View File
@@ -1005,23 +1005,36 @@ def _validate_fetch_url(url: str) -> None:
def _fetch_url_sync(url: str) -> bytes:
_validate_fetch_url(url)
import requests as _req
_MAX_REDIRECTS = 5
current_url = url
try:
resp = _req.get(
url,
headers={"Accept": "text/turtle, application/rdf+xml, application/ld+json, */*;q=0.1"},
timeout=30,
stream=True,
allow_redirects=True,
)
resp.raise_for_status()
chunks: List[bytes] = []
total = 0
for chunk in resp.iter_content(65536):
total += len(chunk)
if total > _MAX_FETCH_BYTES:
raise HTTPException(status_code=413, detail="Remote resource exceeds 20 MB limit.")
chunks.append(chunk)
return b"".join(chunks)
for _ in range(_MAX_REDIRECTS + 1):
resp = _req.get(
current_url,
headers={"Accept": "text/turtle, application/rdf+xml, application/ld+json, */*;q=0.1"},
timeout=30,
stream=True,
allow_redirects=False, # SECURITY: follow redirects manually
)
if resp.is_redirect or resp.is_permanent_redirect:
redirect_url = resp.headers.get("Location")
if not redirect_url:
raise HTTPException(status_code=502, detail="Redirect without Location header.")
# Re-validate the redirect target to prevent SSRF via
# open-redirect to internal/cloud-metadata endpoints.
_validate_fetch_url(redirect_url)
current_url = redirect_url
continue
resp.raise_for_status()
chunks: List[bytes] = []
total = 0
for chunk in resp.iter_content(65536):
total += len(chunk)
if total > _MAX_FETCH_BYTES:
raise HTTPException(status_code=413, detail="Remote resource exceeds 20 MB limit.")
chunks.append(chunk)
return b"".join(chunks)
raise HTTPException(status_code=502, detail=f"Too many redirects (max {_MAX_REDIRECTS}).")
except HTTPException:
raise
except Exception as exc: