The first cut of the per-request interceptor called route.resume() for every
request. Playwright follows server-side 3xx redirects internally on resume()
WITHOUT re-invoking the route handler, so a public page that 302s to a
metadata IP still reached it — verified via runtime E2E (the handler only ever
saw the httpbin.org URLs, never the 169.254.169.254 redirect target).
Fix: for navigation requests, fetch with maxRedirects=0 and validate the
Location of each hop through UrlSafetyChecker before fulfilling; abort when a
hop resolves to a blocked host. Subresources/fetches keep the direct per-URL
check + resume path. Non-navigation and non-http(s) requests are unaffected.
Runtime-verified: httpbin.org 302 -> 169.254.169.254 is now aborted
(net::ERR_FAILED; log "blocked redirect ... cloud-metadata endpoint"), while
example.com and wikipedia.org (rich subresources) still load with no false
blocks.
Two SSRF hardenings on top of the private-network deployment mode:
1. Redirect / subresource re-validation. The SSRF guard previously ran only on
the initial navigation URL in the tool layer, so a public page that 302s to
169.254.169.254 (or a script fetch / img to a metadata IP) reached the target
unchecked — worse now that private-network mode exists. Install a per-context
request interceptor (BrowserLauncher.applyContextDefaults) that re-runs
UrlSafetyChecker on every http(s) request and aborts blocked ones. Non-network
schemes (data:/blob:/about:) pass through; unexpected checker faults fail open
so a transient error cannot wedge the page (the initial URL was already checked).
2. Allowlist can no longer open a cloud-metadata endpoint. Metadata hostnames and
IPs are now checked BEFORE the allowlist short-circuits, so an operator entry
like 169.254.0.0/16 or metadata.google.internal can never expose instance
metadata. Ordinary private-host allowlisting is unaffected (regression-tested).
Also correct the 192.0.0.192 comment (Oracle Cloud IMDS, not Azure).
The per-context setIgnoreHTTPSErrors was gated on ignoreHttpsErrors alone,
while the Chromium command-line cert flags require both ignoreHttpsErrors AND
allowPrivateNetwork. Setting only PLAYWRIGHT_IGNORE_HTTPS_ERRORS therefore
disabled certificate validation for all browser traffic, including the public
internet (MITM exposure). Gate the per-context bypass on allowPrivateNetwork
too, so ignoring HTTPS errors is scoped to LAN deployments — matching the
command-line path and the documented intent.
Also correct a comment: 192.0.0.192 is Oracle Cloud's IMDS address, not Azure.
Add a single global-proxy switch that routes the backend's outbound traffic
through a configured HTTP/HTTPS/SOCKS proxy, for deployments that cannot reach
overseas APIs directly or must use a unified egress.
- ProxyManager installs the proxy via a default ProxySelector (honored by
java.net.http and HttpURLConnection), the proxy system properties, and a
--proxy-server arg for the browser tool; restores direct egress when
disabled. One switch covers LLM, web search, media generation, channels,
MCP and the browser.
- SOCKS applies to the HttpURLConnection-based egress only; the java.net.http
LLM/streaming path uses an HTTP proxy, and the UI states this.
- New Settings -> Network Proxy page: enable toggle, address, bypass list,
test-connection, and a coverage summary. Config stored as key/value in
mate_system_setting (no migration).
refs #109