Skip to content

feat(browser): support allowed_private_hosts for browser tools#8171

Open
NiuBlibing wants to merge 1 commit into
zeroclaw-labs:masterfrom
NiuBlibing:worktree-browser-allow-private-hosts
Open

feat(browser): support allowed_private_hosts for browser tools#8171
NiuBlibing wants to merge 1 commit into
zeroclaw-labs:masterfrom
NiuBlibing:worktree-browser-allow-private-hosts

Conversation

@NiuBlibing

Copy link
Copy Markdown
Contributor

Summary

  • Base branch: master
  • What changed and why:
    • Add [browser].allowed_private_hosts so the browser and browser_open tools can reach operator-listed private/LAN hosts — previously any private host was unconditionally blocked, with no escape hatch (only http_request/web_fetch had one). This unblocks legitimate internal-service automation.
    • Mirror the existing http_request design: exact/subdomain matches, and ["*"] permits all private/local hosts.
    • Listed private hosts bypass the SSRF block and the allowed_domains allowlist; the wildcard is scoped to private hosts only and never widens public reach.
  • Scope boundary: Does not loosen URL schemes — browser_open stays HTTPS-only and file:// stays blocked everywhere. Does not touch http_request/web_fetch/text_browser/browser_delegate or the shared domain_guard SSRF logic. No DNS-rebinding posture change.
  • Blast radius: browser/browser_open tool registration in zeroclaw-runtime; the [browser] config surface. Deny-by-default means zero behavior change unless an operator opts in.
  • Linked issue(s): None.
  • Labels: risk: high (touches crates/zeroclaw-tools/src/** SSRF access-control boundary per AGENTS.md), size: M — maintainers own final risk/size.

Validation Evidence (required)

cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test -p zeroclaw-tools -p zeroclaw-config -p zeroclaw-runtime --lib --tests
  • Commands run and tail output:
    • cargo fmt --all -- --check → clean, exit 0.
    • cargo clippy --workspace --all-targets -- -D warningsFinished \dev` profile ... in 13m 37s`, exit 0, zero warnings across all crates.
    • Tests (lib + integration):
      • zeroclaw-tools lib: test result: ok. 1353 passed; 0 failed
      • zeroclaw-config lib: ok. 942 passed; 0 failed; tests/migration.rs: ok. 90 passed; tests/comment_writer.rs: ok. 8 passed
      • zeroclaw-runtime lib: 2342 passed; 1 failed — the one failure is cron::store::tests::remove_job_emits_structured_cron_delete_event, unrelated to this diff (cron module). It passes in isolation (ok. 1 passed); it shares global log-capture state (__private_test_writer_lock / subscribe_or_install) and races other tests under parallel run. Pre-existing flake.
  • Beyond CI — what did you manually verify? Hand-traced every validate_url branch in both tools for {public,private}×{listed,unlisted}×{http,https}. Added adversarial tests: wildcard private allowlist does not widen the public allowed_domains allowlist; file:// stays blocked even with ["*"]; empty list still denies all private hosts; private host bypasses allowed_domains only when listed. Not verified: live agent-browser/system-browser execution against a real internal host — validation is at the URL-gate layer; no live network was exercised.
  • If any command was intentionally skipped, why: cargo test --doc for zeroclaw-config skipped — pre-existing rustdoc env failure (error: Option 'default-theme' given more than once; rustdoc invoked with --default-theme=ayu twice), reproduced on a clean tree via git stash, independent of this change.

Security & Privacy Impact (required)

  • New permissions, capabilities, or file system access scope? Yes — adds an opt-in capability for browser/browser_open to reach operator-listed private/LAN hosts that were previously always blocked. Off by default (empty list = deny).
  • New external network calls? No — no new call sites; only which hosts pass validation changes.
  • Secrets / tokens / credentials handling changed? No.
  • PII, real identities, or personal data in diff, tests, fixtures, or docs? No — fixtures/tests use only RFC1918 addresses, localhost, and example.com.
  • Risk & mitigation: This is an SSRF-control relaxation, so it is strictly opt-in and deny-by-default. The wildcard is scoped to private hosts only — a ["*"] in allowed_private_hosts never grants access to public hosts (those still flow through allowed_domains). file:// remains blocked; browser_open remains HTTPS-only. No change to DNS-rebinding posture or the shared domain_guard matcher.

Compatibility (required)

  • Backward compatible? Yes — new field defaults to empty; existing configs behave exactly as before.
  • Config / env / CLI surface changed? Yes — adds [browser].allowed_private_hosts (Vec<String>, default []).
  • Upgrade steps: None required. To opt in, set [browser].allowed_private_hosts = ["10.0.0.5", "internal.local"] (or ["*"] for all private hosts).

Rollback (required for risk: medium and risk: high)

  • Fast rollback command/path: git revert 3fe8e6b5b2.
  • Feature flags or config toggles: [browser].allowed_private_hosts — set to [] (the default) to fully disable; no rebuild needed.
  • Observable failure symptoms: browser/browser_open reaching unexpected internal hosts; in logs, an unexpected drop in Blocked local/private host rejections or tool-open events targeting RFC1918 / link-local / metadata addresses.

Add `[browser].allowed_private_hosts` so the `browser` and `browser_open`
tools can reach explicitly listed private/LAN hosts (or `["*"]` for all),
mirroring the existing `http_request` escape hatch.

Listed private hosts bypass the SSRF block and the `allowed_domains`
allowlist; everything else is unchanged. Default is empty (deny-by-default,
fully backward compatible), public hosts still flow through `allowed_domains`,
`file://` stays blocked, and `browser_open` remains HTTPS-only.
@github-actions github-actions Bot added config Auto scope: src/config/** changed. runtime Auto scope: src/runtime/** changed. tool Auto scope: src/tools/** changed. tool:browser Auto module: tool/browser changed. labels Jun 22, 2026
@Audacity88 Audacity88 added enhancement New feature or request security Auto scope: src/security/** changed. security:policy Auto module: security/policy changed. domain:security Security domain risk: high Auto risk: security/runtime/gateway/tools/workflows. size: M Auto size: 251-500 non-doc changed lines. labels Jun 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

config Auto scope: src/config/** changed. domain:security Security domain enhancement New feature or request risk: high Auto risk: security/runtime/gateway/tools/workflows. runtime Auto scope: src/runtime/** changed. security:policy Auto module: security/policy changed. security Auto scope: src/security/** changed. size: M Auto size: 251-500 non-doc changed lines. tool:browser Auto module: tool/browser changed. tool Auto scope: src/tools/** changed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants