Skip to content

fix(browser): allow local sidecar sessions to bypass SSRF guard - #45133

Closed
liuhao1024 wants to merge 3 commits into
NousResearch:mainfrom
liuhao1024:fix/browser-eval-private-network-bypass-v3
Closed

fix(browser): allow local sidecar sessions to bypass SSRF guard#45133
liuhao1024 wants to merge 3 commits into
NousResearch:mainfrom
liuhao1024:fix/browser-eval-private-network-bypass-v3

Conversation

@liuhao1024

Copy link
Copy Markdown
Contributor

What does this PR do?

Extends the private-network guard in browser_snapshot() and browser_vision() to allow local sidecar sessions (hybrid routing) to access private URLs. The previous implementation blocked all private URLs, including those accessed via local sidecar sessions where the cloud provider never sees the URL.

Related Issue

Fixes #44731 (original SSRF bypass issue)
Addresses review feedback from egilewski on #45101

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • tools/browser_tool.py: Add _is_local_sidecar_key(effective_task_id) check to both browser_snapshot() and browser_vision() private-network guards, matching the existing pattern in browser_navigate()
  • tests/tools/test_browser_snapshot_ssrf.py: Add test_skips_check_for_local_sidecar_session tests for both snapshot and vision guards

How to Test

  1. Run the SSRF tests: pytest tests/tools/test_browser_snapshot_ssrf.py -v
  2. Run the local sidecar tests: pytest tests/tools/test_browser_ssrf_local.py -v
  3. Verify that local sidecar sessions can access private URLs (e.g., http://192.168.1.1/admin) without being blocked
  4. Verify that cloud sessions still block private URLs unless allow_private_urls is enabled

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Code Intelligence

browser_snapshot() now checks the current page URL before returning
content. When browser_console() changes location.href to a private or
internal address (e.g., http://127.0.0.1:8080/), the snapshot returns
an error instead of exposing the private page content.

This closes the SSRF bypass where an attacker could:
1. Navigate to a public page
2. Use browser_console to eval location.href = 'http://127.0.0.1:port/'
3. Use browser_snapshot to read the private page content

The fix reuses the existing _is_safe_url() and _allow_private_urls()
infrastructure, and fails open if the URL check itself fails.

Fixes NousResearch#44731
The SSRF bypass in NousResearch#44731 was only patched for browser_snapshot(), but
browser_vision() exposes the same vulnerability — it takes a screenshot
and sends it to the vision model without checking if eval-driven
navigation moved the page to a private/internal URL.

Add the same current-page URL safety check to browser_vision() before
any screenshot is captured, encoded, or forwarded to the vision model.
This covers both the normal screenshot path and the Lightpanda Chrome
fallback path.

7 new tests: blocks private URL, allows public URL, skips in local
backend, skips when private URLs allowed, handles eval failure/empty/exception.
The private-network guard in browser_snapshot() and browser_vision()
blocked all private URLs, including those accessed via local sidecar
sessions (hybrid routing). Local sidecar sessions intentionally access
private URLs — the cloud provider never sees the URL in that case.

Add `_is_local_sidecar_key(effective_task_id)` check to both guards,
matching the existing pattern in browser_navigate().

Fixes NousResearch#45101 review feedback from egilewski.
@teknium1

Copy link
Copy Markdown
Contributor

Merged via PR #54132 (rebase-merged). Your three commits were cherry-picked onto current main with your authorship preserved in git log (7a6fe9b, 48f5c42, 0ae6196). We added a sibling commit on top that closes the eval return-value path (direct private fetch + navigate-then-read via browser_console), so the SSRF guard now covers navigate/snapshot/vision/eval. Thanks for the snapshot+vision fix and for iterating through the local-sidecar feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Medium — degraded but workaround exists tool/browser Browser automation (CDP, Playwright) type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Security] Hermes browser private-network policy bypass via eval-triggered main-frame navigation

3 participants