Skip to content

fix(browser): block Camofox private redirects before auto-snapshot - #57394

Open
necoweb3 wants to merge 2 commits into
NousResearch:mainfrom
necoweb3:fix/camofox-navigate-private-redirect
Open

fix(browser): block Camofox private redirects before auto-snapshot#57394
necoweb3 wants to merge 2 commits into
NousResearch:mainfrom
necoweb3:fix/camofox-navigate-private-redirect

Conversation

@necoweb3

@necoweb3 necoweb3 commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Summary

This adds post-navigation redirect checks to the Camofox browser backend before camofox_navigate() returns a result or takes its automatic compact snapshot.

Why

The main browser_navigate() path already blocks redirects that land on cloud metadata or private/internal addresses before returning page state. The Camofox path delegated to camofox_navigate() after the initial URL safety checks, but camofox_navigate() did not re-check the final URL returned by the Camofox backend.

That left a sibling path where a public URL could redirect Camofox to an internal/private page and camofox_navigate() would proceed to take its auto-snapshot. On a non-local Camofox backend, this can expose private network content the terminal itself cannot reach.

There was also a first-tab edge case: _ensure_tab() received the backend's created-tab URL but discarded it, so first navigations could not inspect the final URL before the auto-snapshot.

Changes

  • Preserve the created tab's returned URL from _ensure_tab().
  • Check the final Camofox navigation URL before building the success payload.
  • Block cloud metadata redirects unconditionally.
  • Block private/internal redirects when the browser SSRF guard is active.
  • Best-effort navigate the Camofox tab to about:blank after a blocked redirect.
  • Add regression tests proving blocked redirects do not run the Camofox auto-snapshot.

Tests

python -m pytest tests/tools/test_browser_camofox.py -k "CamofoxNavigate or metadata_redirect or private_redirect" -q --timeout-method=thread
6 passed

python -m pytest tests/tools/test_browser_camofox.py::TestCamofoxNavigate::test_blocks_metadata_redirect_before_auto_snapshot tests/tools/test_browser_camofox.py::TestCamofoxNavigate::test_blocks_private_redirect_when_guard_active tests/tools/test_browser_camofox_private_page_guard.py -q --timeout-method=thread
7 passed

python -m ruff check tools/browser_camofox.py tests/tools/test_browser_camofox.py

@alt-glitch alt-glitch added type/security Security vulnerability or hardening tool/browser Browser automation (CDP, Playwright) sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data P1 High — major feature broken, no workaround labels Jul 2, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related: completes the browser SSRF cluster by covering the Camofox sink. Sibling merged fixes: #54132 (snapshot/vision/eval), #54435 (get_images), #56173 (interaction sinks), #56373 (console output), #56526 (browser_back). Distinct navigation sink/mechanism, so this is complementary — not a duplicate. Cluster floor P1 (exploitable SSRF on a non-local Camofox backend, clear vector).

@egilewski

Copy link
Copy Markdown
Contributor

suggesting changes

Security evidence:

  • trust boundary: Camofox runs as the browser backend and can reach network locations the terminal cannot, so camofox_navigate() must block metadata/private final URLs before it reads page state.
  • source/sink/invariant: the source is the final URL returned by the Camofox backend when a tab is created or recreated; the sink is the automatic /tabs/{tab_id}/snapshot read; the invariant is that every backend-reported final URL is checked before snapshot content is fetched.
  • current-main reproduction: current main has no post-navigation final-URL check in camofox_navigate(), so a public URL that lands on 169.254.169.254 can proceed into the auto-snapshot path.
  • PR-head or patch-replay validation: replaying this patch onto current main blocks the new first-tab metadata redirect and guard-active private redirect tests, and TestCamofoxNavigate passes as 6 passed.
  • positive/negative cases: the new tests cover the first-tab metadata/private redirect paths and preserve existing navigation behavior, but they do not cover stale-tab recovery.
  • residual bypass search: the stale-tab 404 recovery branch still recreates the tab with _ensure_tab(), then sets data = {"ok": True, "url": browser_url} instead of using the recreated tab's returned URL. In the patch-replay worktree, a run-root probe where the recreated tab returned http://169.254.169.254/latest/meta-data/ produced result_success=True, snapshot_present=True, and two GET calls, so the auto-snapshot still ran on the blocked redirect.

Please carry the backend-returned created-tab URL through the stale-tab recovery path as well, and add a regression test where a stale tab 404 is followed by a recreated tab landing on metadata/private URL before any snapshot is attempted.

Signed: GPT-5.5-xhigh in Codex

@necoweb3

necoweb3 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

suggesting changes

Security evidence:

  • trust boundary: Camofox runs as the browser backend and can reach network locations the terminal cannot, so camofox_navigate() must block metadata/private final URLs before it reads page state.
  • source/sink/invariant: the source is the final URL returned by the Camofox backend when a tab is created or recreated; the sink is the automatic /tabs/{tab_id}/snapshot read; the invariant is that every backend-reported final URL is checked before snapshot content is fetched.
  • current-main reproduction: current main has no post-navigation final-URL check in camofox_navigate(), so a public URL that lands on 169.254.169.254 can proceed into the auto-snapshot path.
  • PR-head or patch-replay validation: replaying this patch onto current main blocks the new first-tab metadata redirect and guard-active private redirect tests, and TestCamofoxNavigate passes as 6 passed.
  • positive/negative cases: the new tests cover the first-tab metadata/private redirect paths and preserve existing navigation behavior, but they do not cover stale-tab recovery.
  • residual bypass search: the stale-tab 404 recovery branch still recreates the tab with _ensure_tab(), then sets data = {"ok": True, "url": browser_url} instead of using the recreated tab's returned URL. In the patch-replay worktree, a run-root probe where the recreated tab returned http://169.254.169.254/latest/meta-data/ produced result_success=True, snapshot_present=True, and two GET calls, so the auto-snapshot still ran on the blocked redirect.

Please carry the backend-returned created-tab URL through the stale-tab recovery path as well, and add a regression test where a stale tab 404 is followed by a recreated tab landing on metadata/private URL before any snapshot is attempted.

Signed: GPT-5.5-xhigh in Codex

Updated, thanks for catching the stale-tab recovery gap.

The branch now carries the backend-returned recreated-tab URL through the 404 recovery path (session.get("_last_url") or browser_url) before running the same final-URL guard. I also added a regression test where:

  • an existing Camofox tab returns 404 during navigate,
  • _ensure_tab() recreates it and the backend reports http://169.254.169.254/latest/meta-data/,
  • the navigation is blocked,
  • the tab is cleared to about:blank,
  • and no auto-snapshot is attempted for the recreated metadata tab.

Validation:

python -m pytest tests/tools/test_browser_camofox.py -k "Navigate" -q
8 passed, 25 deselected

python -m pytest tests/tools/test_browser_camofox_private_page_guard.py -q
5 passed

python -m pytest tests/tools/test_browser_camofox.py tests/tools/test_browser_camofox_private_page_guard.py -q
38 passed

@alt-glitch alt-glitch added P2 Medium — degraded but workaround exists and removed P1 High — major feature broken, no workaround labels Jul 3, 2026
@alt-glitch alt-glitch added P1 High — major feature broken, no workaround P2 Medium — degraded but workaround exists and removed P2 Medium — degraded but workaround exists P1 High — major feature broken, no workaround labels Jul 3, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for covering the remaining Camofox navigation sink. Current main still discards the created-tab response URL in _ensure_tab() (tools/browser_camofox.py:415-417), substitutes the requested URL on both creation and stale-tab recovery (tools/browser_camofox.py:497-518), and then fetches the automatic snapshot (tools/browser_camofox.py:541-546) without a final-URL check.

The proposed final-URL guard follows the established non-Camofox redirect behavior in tools/browser_tool.py:2820-2853, including the unconditional metadata floor and best-effort navigation to about:blank. The PR also covers the first-tab and stale-404 recreation paths discussed in the review thread. Existing main guards already cover Camofox content reads and input actions (tools/browser_camofox.py:615-617, 656-658, 795-797, 843-845), so this is the missing navigation-specific complement.

Automated hermes-sweeper review.

@alt-glitch alt-glitch added P3 Low — cosmetic, nice to have and removed P2 Medium — degraded but workaround exists labels Jul 15, 2026
@teknium1 teknium1 added the sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users label Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low — cosmetic, nice to have sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data tool/browser Browser automation (CDP, Playwright) type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants