fix(browser): enable SSRF guard when terminal runs in container

When terminal.backend is docker/modal/daytona/ssh/singularity, the
terminal runs in a sandboxed container with network isolation, but the
browser still runs on the host.  The SSRF guard was skipped because
_is_local_backend() only checked browser.cloud_provider, not the
terminal backend.

Now _is_local_backend() also checks TERMINAL_ENV — when the terminal
is containerized, the browser is treated as non-local and SSRF
protection is enabled.

Fixes #38690
This commit is contained in:
liuhao1024 2026-06-04 12:13:53 +08:00 committed by Teknium
parent c7e8854cb3
commit 6984026f12
2 changed files with 47 additions and 2 deletions

View file

@ -190,6 +190,39 @@ class TestIsLocalBackend:
assert browser_tool._is_local_backend() is False
@pytest.mark.parametrize("backend", ["docker", "modal", "daytona", "ssh", "singularity"])
def test_container_terminal_backend_is_not_local(self, monkeypatch, backend):
"""Terminal running in a container → NOT local (browser on host can access internal networks)."""
monkeypatch.setattr(browser_tool, "_is_camofox_mode", lambda: False)
monkeypatch.setattr(browser_tool, "_get_cloud_provider", lambda: None)
monkeypatch.setenv("TERMINAL_ENV", backend)
assert browser_tool._is_local_backend() is False
def test_empty_terminal_env_is_local(self, monkeypatch):
"""Empty TERMINAL_ENV → local backend."""
monkeypatch.setattr(browser_tool, "_is_camofox_mode", lambda: False)
monkeypatch.setattr(browser_tool, "_get_cloud_provider", lambda: None)
monkeypatch.setenv("TERMINAL_ENV", "")
assert browser_tool._is_local_backend() is True
def test_local_terminal_env_is_local(self, monkeypatch):
"""Explicit 'local' TERMINAL_ENV → local backend."""
monkeypatch.setattr(browser_tool, "_is_camofox_mode", lambda: False)
monkeypatch.setattr(browser_tool, "_get_cloud_provider", lambda: None)
monkeypatch.setenv("TERMINAL_ENV", "local")
assert browser_tool._is_local_backend() is True
def test_camofox_overrides_container_backend(self, monkeypatch):
"""Camofox mode always counts as local, even with container terminal."""
monkeypatch.setattr(browser_tool, "_is_camofox_mode", lambda: True)
monkeypatch.setattr(browser_tool, "_get_cloud_provider", lambda: None)
monkeypatch.setenv("TERMINAL_ENV", "docker")
assert browser_tool._is_local_backend() is True
# ---------------------------------------------------------------------------
# Post-redirect SSRF check

View file

@ -619,7 +619,7 @@ def _is_local_mode() -> bool:
def _is_local_backend() -> bool:
"""Return True when the browser runs locally (no cloud provider).
"""Return True when the browser runs locally AND the terminal is also local.
SSRF protection is only meaningful for cloud backends (Browserbase,
BrowserUse) where the agent could reach internal resources on a remote
@ -627,8 +627,20 @@ def _is_local_backend() -> bool:
Chromium without a cloud provider the user already has full terminal
and network access on the same machine, so the check adds no security
value.
However, when the terminal runs in a container (docker, modal, daytona,
ssh, singularity), the browser on the host can access internal networks
that the terminal cannot. In this case, SSRF protection should be
enabled even though the browser is technically "local".
"""
return _is_camofox_mode() or _get_cloud_provider() is None
if _is_camofox_mode():
return True
if _get_cloud_provider() is not None:
return False
# When terminal runs in a container, browser on host can access
# internal networks the terminal can't → treat as non-local.
terminal_backend = os.getenv("TERMINAL_ENV", "local").strip().lower()
return terminal_backend in ("local", "")
_auto_local_for_private_urls_resolved = False