Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions invokeai/app/util/ssrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,21 @@ def init_poolmanager(self, *args: Any, **kwargs: Any) -> None:
"https": _GuardedHTTPSConnectionPool,
}

def proxy_manager_for(self, proxy: str, **proxy_kwargs: Any) -> Any:
"""Install the socket guard on proxy pools as well as direct pools.

Requests creates proxy managers separately from the adapter's direct pool
manager. Without replacing their pool classes, an explicit download proxy
would use urllib3's ordinary connection classes and bypass the peer-address
check entirely.
"""
manager = super().proxy_manager_for(proxy, **proxy_kwargs)
manager.pool_classes_by_scheme = {
"http": _GuardedHTTPConnectionPool,
"https": _GuardedHTTPSConnectionPool,
}
return manager


class _SsrfGuardedSession(requests.Session):
"""Session that keeps Requests environment support but drops ambient proxies."""
Expand Down
11 changes: 11 additions & 0 deletions tests/app/util/test_ssrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,17 @@ def test_guarded_session_is_installed_for_both_schemes():
assert adapter.poolmanager.pool_classes_by_scheme["https"] is ssrf._GuardedHTTPSConnectionPool


def test_guarded_session_applies_socket_guard_to_explicit_proxy(loopback_server: int):
"""An explicit proxy must not bypass the connected-peer address check."""
session = build_guarded_session(proxy=f"http://127.0.0.1:{loopback_server}")
try:
with pytest.raises(Exception) as excinfo:
session.get("http://example.com/internal", timeout=5)
assert _unsafe_in_chain(excinfo.value)
finally:
session.close()


@pytest.mark.parametrize(
"url",
[
Expand Down
Loading