feat(browser): support allowed_private_hosts for browser tools#8171
Open
NiuBlibing wants to merge 1 commit into
Open
feat(browser): support allowed_private_hosts for browser tools#8171NiuBlibing wants to merge 1 commit into
NiuBlibing wants to merge 1 commit into
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
master[browser].allowed_private_hostsso thebrowserandbrowser_opentools can reach operator-listed private/LAN hosts — previously any private host was unconditionally blocked, with no escape hatch (onlyhttp_request/web_fetchhad one). This unblocks legitimate internal-service automation.http_requestdesign: exact/subdomain matches, and["*"]permits all private/local hosts.allowed_domainsallowlist; the wildcard is scoped to private hosts only and never widens public reach.browser_openstays HTTPS-only andfile://stays blocked everywhere. Does not touchhttp_request/web_fetch/text_browser/browser_delegateor the shareddomain_guardSSRF logic. No DNS-rebinding posture change.browser/browser_opentool registration inzeroclaw-runtime; the[browser]config surface. Deny-by-default means zero behavior change unless an operator opts in.risk: high(touchescrates/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 --testscargo fmt --all -- --check→ clean, exit 0.cargo clippy --workspace --all-targets -- -D warnings→Finished \dev` profile ... in 13m 37s`, exit 0, zero warnings across all crates.zeroclaw-toolslib:test result: ok. 1353 passed; 0 failedzeroclaw-configlib:ok. 942 passed; 0 failed;tests/migration.rs:ok. 90 passed;tests/comment_writer.rs:ok. 8 passedzeroclaw-runtimelib:2342 passed; 1 failed— the one failure iscron::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.validate_urlbranch in both tools for {public,private}×{listed,unlisted}×{http,https}. Added adversarial tests: wildcard private allowlist does not widen the publicallowed_domainsallowlist;file://stays blocked even with["*"]; empty list still denies all private hosts; private host bypassesallowed_domainsonly 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.cargo test --docforzeroclaw-configskipped — pre-existing rustdoc env failure (error: Option 'default-theme' given more than once; rustdoc invoked with--default-theme=ayutwice), reproduced on a clean tree viagit stash, independent of this change.Security & Privacy Impact (required)
browser/browser_opento reach operator-listed private/LAN hosts that were previously always blocked. Off by default (empty list = deny).localhost, andexample.com.["*"]inallowed_private_hostsnever grants access to public hosts (those still flow throughallowed_domains).file://remains blocked;browser_openremains HTTPS-only. No change to DNS-rebinding posture or the shareddomain_guardmatcher.Compatibility (required)
[browser].allowed_private_hosts(Vec<String>, default[]).[browser].allowed_private_hosts = ["10.0.0.5", "internal.local"](or["*"]for all private hosts).Rollback (required for
risk: mediumandrisk: high)git revert 3fe8e6b5b2.[browser].allowed_private_hosts— set to[](the default) to fully disable; no rebuild needed.browser/browser_openreaching unexpected internal hosts; in logs, an unexpected drop inBlocked local/private hostrejections or tool-open events targeting RFC1918 / link-local / metadata addresses.