Skip to content

fix(browser): block private-page interactions after eval navigation (salvage #55949) - #56173

Merged
kshitijk4poor merged 2 commits into
NousResearch:mainfrom
kshitijk4poor:salvage-55949
Jul 1, 2026
Merged

fix(browser): block private-page interactions after eval navigation (salvage #55949)#56173
kshitijk4poor merged 2 commits into
NousResearch:mainfrom
kshitijk4poor:salvage-55949

Conversation

@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Summary

Salvage of #55949 (rebased onto current main + review follow-up). Blocks state-changing browser interactions (browser_click, browser_type, browser_press) when a cloud-browser page has landed on a private/internal URL after JavaScript-driven navigation.

Original PR #55949 by @necoweb3 was 67 commits behind main. Its commit is cherry-picked here verbatim (authorship preserved) and rebased onto current main, plus one review follow-up commit under my identity.

Why

Recent browser SSRF hardening (#54132, #54435, #54477) covers content-returning paths — browser_snapshot, browser_vision, browser_console, browser_get_images — which re-check the current page URL after eval-driven navigation and refuse to return private-network content.

The state-changing interaction sinks had no sibling guard. If a page was navigated to a private/internal URL through an eval-driven path (e.g. location.href = 'http://169.254.169.254/...' via browser_console), browser_click, browser_type, and browser_press would still send input to that page. In cloud-browser mode that crosses the same private-network boundary — as a side-effect primitive rather than a read primitive. Reproduced on current main: click/type/press all reach _run_browser_command on a synthetic private page, and browser_type echoes the typed sentinel back.

Changes

  • Add a shared private-page action guard _blocked_private_page_action in tools/browser_tool.py.
  • Refuse browser_click, browser_type, and browser_press when the current cloud-browser page is private/internal.
  • Reuse the existing _eval_ssrf_guard_active() and _current_page_private_url() checks (identical fail-open-on-probe-error semantics as the snapshot/vision/eval guards).
  • Leave local/Camofox behavior unchanged (camofox early-return precedes the guard).
  • Leave non-state-changing navigation helpers (back, scroll) unchanged — they send no attacker-controlled input to the page.

Review follow-up (this salvage)

  • Add test_guard_inactive_does_not_block_or_probe — the guard-inactive branch (local backend / allow_private_urls) must proceed WITHOUT probing the page URL. This was the untested branch most likely to silently regress if the condition is inverted; a mutation check (flipping if not ...if ...) confirms the new test fails as designed.
  • Add test_camofox_short_circuits_before_guard — asserts the camofox early-return precedes the guard so its helpers are never consulted in local/Camofox mode.
  • Fix PEP8: 3 → 2 blank lines before the helper.

Tests

python -m pytest tests/tools/test_browser_private_page_action_guard.py -q --timeout-method=thread
6 passed

python -m pytest tests/tools/test_browser_private_page_action_guard.py \
  tests/tools/test_browser_eval_ssrf.py tests/tools/test_browser_get_images_ssrf.py \
  tests/tools/test_browser_snapshot_ssrf.py -q --timeout-method=thread
40 passed

Full browser suite: 458 passed, 3 failed (pre-existing test_browser_secret_exfil.py::TestWebExtractSecretExfil, unrelated — verified identical on HEAD~1), 30 skipped. This change introduces zero new failures.

Supersedes #55949. Credit to @necoweb3 for the original fix.

necoweb3 and others added 2 commits July 1, 2026 13:41
…x blank lines

Review follow-up on the private-page action guard:
- Add test_guard_inactive_does_not_block_or_probe: when the SSRF guard is
  inactive (local backend / allow_private_urls), click/type/press must proceed
  WITHOUT probing the page URL. This is the branch most likely to silently
  regress if the guard condition is inverted; a mutation check (flipping the
  condition) confirms the test fails as designed.
- Add test_camofox_short_circuits_before_guard: camofox mode returns from the
  dedicated camofox_* path before the guard runs; guards never consulted.
- Fix PEP8: 3 -> 2 blank lines before _blocked_private_page_action.
@kshitijk4poor
kshitijk4poor merged commit 83ae654 into NousResearch:main Jul 1, 2026
31 checks passed
@alt-glitch alt-glitch added type/security Security vulnerability or hardening P1 High — major feature broken, no workaround tool/browser Browser automation (CDP, Playwright) sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data labels Jul 1, 2026
@kshitijk4poor
kshitijk4poor deleted the salvage-55949 branch July 1, 2026 10:09
kshitijk4poor pushed a commit to kshitijk4poor/hermes-agent that referenced this pull request Jul 2, 2026
Extends the browser private-network eval guard to the Camofox backend.
On main, _browser_eval() returned early in Camofox mode before running the
shared private-URL literal pre-scan and before re-checking the page URL
after eval, leaving Camofox as a sibling backend that could execute
browser_console(expression=...) against private/internal targets.

- move the eval private-URL literal pre-scan before the Camofox early return
- add a Camofox current-page private-URL probe via the evaluate endpoint
- withhold Camofox eval results when the page is now private/internal

Follow-up to browser private-network hardening in NousResearch#56173, NousResearch#56526, NousResearch#56664.

Salvage of NousResearch#56764 by @rayjun (rayoo), cherry-picked to preserve authorship.
kshitijk4poor pushed a commit that referenced this pull request Jul 2, 2026
Extends the browser private-network eval guard to the Camofox backend.
On main, _browser_eval() returned early in Camofox mode before running the
shared private-URL literal pre-scan and before re-checking the page URL
after eval, leaving Camofox as a sibling backend that could execute
browser_console(expression=...) against private/internal targets.

- move the eval private-URL literal pre-scan before the Camofox early return
- add a Camofox current-page private-URL probe via the evaluate endpoint
- withhold Camofox eval results when the page is now private/internal

Follow-up to browser private-network hardening in #56173, #56526, #56664.

Salvage of #56764 by @rayjun (rayoo), cherry-picked to preserve authorship.
Jasper6439 pushed a commit to Jasper6439/hermes-agent that referenced this pull request Jul 5, 2026
Extends the browser private-network eval guard to the Camofox backend.
On main, _browser_eval() returned early in Camofox mode before running the
shared private-URL literal pre-scan and before re-checking the page URL
after eval, leaving Camofox as a sibling backend that could execute
browser_console(expression=...) against private/internal targets.

- move the eval private-URL literal pre-scan before the Camofox early return
- add a Camofox current-page private-URL probe via the evaluate endpoint
- withhold Camofox eval results when the page is now private/internal

Follow-up to browser private-network hardening in NousResearch#56173, NousResearch#56526, NousResearch#56664.

Salvage of NousResearch#56764 by @rayjun (rayoo), cherry-picked to preserve authorship.
habarmc1223-sudo pushed a commit to habarmc1223-sudo/hermes-agent-fluxmem that referenced this pull request Jul 8, 2026
Extends the browser private-network eval guard to the Camofox backend.
On main, _browser_eval() returned early in Camofox mode before running the
shared private-URL literal pre-scan and before re-checking the page URL
after eval, leaving Camofox as a sibling backend that could execute
browser_console(expression=...) against private/internal targets.

- move the eval private-URL literal pre-scan before the Camofox early return
- add a Camofox current-page private-URL probe via the evaluate endpoint
- withhold Camofox eval results when the page is now private/internal

Follow-up to browser private-network hardening in NousResearch#56173, NousResearch#56526, NousResearch#56664.

Salvage of NousResearch#56764 by @rayjun (rayoo), cherry-picked to preserve authorship.
santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
Extends the browser private-network eval guard to the Camofox backend.
On main, _browser_eval() returned early in Camofox mode before running the
shared private-URL literal pre-scan and before re-checking the page URL
after eval, leaving Camofox as a sibling backend that could execute
browser_console(expression=...) against private/internal targets.

- move the eval private-URL literal pre-scan before the Camofox early return
- add a Camofox current-page private-URL probe via the evaluate endpoint
- withhold Camofox eval results when the page is now private/internal

Follow-up to browser private-network hardening in NousResearch#56173, NousResearch#56526, NousResearch#56664.

Salvage of NousResearch#56764 by @rayjun (rayoo), cherry-picked to preserve authorship.
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
Extends the browser private-network eval guard to the Camofox backend.
On main, _browser_eval() returned early in Camofox mode before running the
shared private-URL literal pre-scan and before re-checking the page URL
after eval, leaving Camofox as a sibling backend that could execute
browser_console(expression=...) against private/internal targets.

- move the eval private-URL literal pre-scan before the Camofox early return
- add a Camofox current-page private-URL probe via the evaluate endpoint
- withhold Camofox eval results when the page is now private/internal

Follow-up to browser private-network hardening in NousResearch#56173, NousResearch#56526, NousResearch#56664.

Salvage of NousResearch#56764 by @rayjun (rayoo), cherry-picked to preserve authorship.
leewenjie pushed a commit to leewenjie/hermes-agent that referenced this pull request Aug 7, 2026
Extends the browser private-network eval guard to the Camofox backend.
On main, _browser_eval() returned early in Camofox mode before running the
shared private-URL literal pre-scan and before re-checking the page URL
after eval, leaving Camofox as a sibling backend that could execute
browser_console(expression=...) against private/internal targets.

- move the eval private-URL literal pre-scan before the Camofox early return
- add a Camofox current-page private-URL probe via the evaluate endpoint
- withhold Camofox eval results when the page is now private/internal

Follow-up to browser private-network hardening in NousResearch#56173, NousResearch#56526, NousResearch#56664.

Salvage of NousResearch#56764 by @rayjun (rayoo), cherry-picked to preserve authorship.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P1 High — major feature broken, no workaround 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.

3 participants