fix(security): block SSRF via user-supplied model endpoint URLs (#6316)

* fix: block SSRF via user-supplied model endpoint URLs

* fix(test): stub DNS in loopback SSRF tests for deterministic results

Replace environment-dependent test_loopback_always_rejected with two
deterministic tests using a stub resolver:
- test_loopback_accepted_by_default (local-first, block_private=False)
- test_loopback_rejected_in_strict_mode (block_private=True)

The old test only passed when localhost resolved to ::1 (hit is_reserved),
not because loopback was actually always rejected.

Co-Authored-By: Santoshkumarpuppala

* fix: guard PATCH base_url against SSRF and add ipv6 loopback coverage

---------

Co-authored-by: isharak7m <192635824+isharak7m@users.noreply.github.com>
This commit is contained in:
Isharak
2026-10-23 13:18:54 -06:00
committed by GitHub
co-authored by Santoshkumarpuppala isharak7m
parent b4ae7ebcc4
commit 0dbf457c00
3 changed files with 333 additions and 0 deletions
+3
View File
@@ -1281,6 +1281,7 @@ def _patch_create_deps(monkeypatch, db, settings=None):
monkeypatch.setattr(model_routes, "_save_settings", lambda s: settings.update(s))
monkeypatch.setattr(endpoint_resolver, "resolve_url", lambda u: u)
monkeypatch.setattr(auth_helpers, "get_current_user", lambda req: None)
monkeypatch.setattr(model_routes, "check_outbound_url", lambda *a, **k: (True, "ok"))
return settings
@@ -2000,6 +2001,7 @@ def test_explicit_proxy_test_fetches_models_with_long_timeout(monkeypatch):
monkeypatch.setattr(model_routes, "require_admin", lambda request: None)
monkeypatch.setattr(model_routes, "_ping_endpoint", lambda *a, **k: (_ for _ in ()).throw(AssertionError("ping should not run when model listing succeeds")))
monkeypatch.setattr(model_routes, "check_outbound_url", lambda *a, **k: (True, "ok"))
calls = []
returned = ["NVIDIA NIM/openai/gpt-oss-120b", "mistral/mistral-small-2603"]
@@ -2038,6 +2040,7 @@ def test_explicit_proxy_add_fetches_and_caches_models_with_long_timeout(monkeypa
monkeypatch.setattr(model_routes, "_save_settings", lambda settings: None)
monkeypatch.setattr("src.auth_helpers.get_current_user", lambda request: None)
monkeypatch.setattr(model_routes, "_ping_endpoint", lambda *a, **k: (_ for _ in ()).throw(AssertionError("ping should not run when model listing succeeds")))
monkeypatch.setattr(model_routes, "check_outbound_url", lambda *a, **k: (True, "ok"))
calls = []
returned = ["NVIDIA NIM/openai/gpt-oss-120b", "mistral/mistral-small-2603"]