fix(browser): apply private-page guard to browser_cdp frame_id routing

browser_cdp's frame_id (OOPIF) path returned early via
_browser_cdp_via_supervisor before _browser_cdp_private_guard ever ran,
unlike the stateless path a few lines below. A model that navigated a
cloud browser to a private/internal URL could still read page content
by passing frame_id, bypassing the same SSRF/private-page boundary
already enforced on Runtime.evaluate, Page.navigate, and other raw CDP
calls.

Apply the same guard call used by the stateless path before dispatching
to the supervisor, so both routing modes share one boundary.
fix/verification-admin-route-recovery
srojk34 2026-07-03 05:18:15 +03:00 committed by Teknium
parent 4470d957cb
commit 47764f19f4
2 changed files with 73 additions and 0 deletions

View File

@ -430,6 +430,70 @@ def test_runtime_evaluate_blocked_when_current_page_is_private(monkeypatch):
assert calls == []
def test_frame_id_route_blocked_when_current_page_is_private(monkeypatch):
"""frame_id routing (OOPIF via supervisor) must not bypass the guard
applied to the stateless path same private-page boundary either way."""
supervisor_calls = []
import tools.browser_tool as bt
monkeypatch.setattr(bt, "_eval_ssrf_guard_active", lambda task_id: True)
monkeypatch.setattr(bt, "_current_page_private_url", lambda task_id: PRIVATE_URL)
def fake_supervisor_route(**kwargs):
supervisor_calls.append(kwargs)
return json.dumps({"success": True, "result": {"value": "private data"}})
monkeypatch.setattr(
browser_cdp_tool, "_browser_cdp_via_supervisor", fake_supervisor_route
)
result = json.loads(
browser_cdp_tool.browser_cdp(
method="Runtime.evaluate",
params={"expression": "document.body.innerText"},
frame_id="frame-1",
task_id="task-1",
)
)
assert "error" in result
assert PRIVATE_URL in result["error"]
assert "private or internal address" in result["error"]
assert supervisor_calls == []
def test_frame_id_route_allowed_when_page_is_not_private(monkeypatch):
"""Sanity check: the new guard call must not block ordinary frame_id
routing when the current page isn't private."""
supervisor_calls = []
import tools.browser_tool as bt
monkeypatch.setattr(bt, "_eval_ssrf_guard_active", lambda task_id: True)
monkeypatch.setattr(bt, "_current_page_private_url", lambda task_id: None)
def fake_supervisor_route(**kwargs):
supervisor_calls.append(kwargs)
return json.dumps({"success": True, "result": {"value": "ok"}})
monkeypatch.setattr(
browser_cdp_tool, "_browser_cdp_via_supervisor", fake_supervisor_route
)
result = json.loads(
browser_cdp_tool.browser_cdp(
method="Runtime.evaluate",
params={"expression": "document.title"},
frame_id="frame-1",
task_id="task-1",
)
)
assert result.get("success") is True
assert len(supervisor_calls) == 1
def test_page_navigate_to_private_url_blocked_before_cdp(monkeypatch):
calls = []

View File

@ -428,6 +428,15 @@ def browser_cdp(
# --- Route iframe-scoped calls through the supervisor ---------------
if frame_id:
# Same private-page/SSRF boundary as the stateless path below —
# frame_id routing must not become the sibling bypass for it.
blocked = _browser_cdp_private_guard(
task_id=effective_task_id,
method=method,
params=params or {},
)
if blocked:
return blocked
return _browser_cdp_via_supervisor(
task_id=effective_task_id,
frame_id=frame_id,