From b1038d66318afb2a50c0fd7f2eabbd43c284282b Mon Sep 17 00:00:00 2001 From: wunianze666-netizen Date: Fri, 28 Aug 2026 15:58:17 +0800 Subject: [PATCH 1/2] fix(ssrf): guard explicit proxy connections --- invokeai/app/util/ssrf.py | 15 +++++++++++++++ tests/app/util/test_ssrf.py | 11 +++++++++++ 2 files changed, 26 insertions(+) diff --git a/invokeai/app/util/ssrf.py b/invokeai/app/util/ssrf.py index 4825c9e1cc0..0d81df7eabf 100644 --- a/invokeai/app/util/ssrf.py +++ b/invokeai/app/util/ssrf.py @@ -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.""" diff --git a/tests/app/util/test_ssrf.py b/tests/app/util/test_ssrf.py index 4cd5f82df7e..58c34a02cd2 100644 --- a/tests/app/util/test_ssrf.py +++ b/tests/app/util/test_ssrf.py @@ -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", [ From e92a43935bdcf3c04ef58ccb41f9c7d973653dcb Mon Sep 17 00:00:00 2001 From: wunianze666-netizen Date: Fri, 11 Sep 2026 12:57:46 +0800 Subject: [PATCH 2/2] test(ssrf): cover HTTPS proxy tunnels --- tests/app/util/test_ssrf.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/app/util/test_ssrf.py b/tests/app/util/test_ssrf.py index 58c34a02cd2..36b8d662eeb 100644 --- a/tests/app/util/test_ssrf.py +++ b/tests/app/util/test_ssrf.py @@ -228,12 +228,19 @@ 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): +@pytest.mark.parametrize( + "target_url", + [ + pytest.param("http://example.com/internal", id="http-proxy-request"), + pytest.param("https://example.com/internal", id="https-connect-tunnel"), + ], +) +def test_guarded_session_applies_socket_guard_to_explicit_proxy(loopback_server: int, target_url: str): """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) + session.get(target_url, timeout=5) assert _unsafe_in_chain(excinfo.value) finally: session.close()