Context
Guion Web sends explicit render=browser requests to the in-cluster browser-gateway POST /api/render endpoint. The web process DNS-resolves the initial requested host and rejects private/reserved results. Gateway also rejects literal private, reserved, and cluster-local hostnames at input and on browser document redirects.
Security debt
-
DNS rebinding / DNS TOCTOU remains possible. Gateway validation is lexical (URL.hostname) and does not resolve a hostname. A hostile hostname can resolve to a public address during Web's initial check, then resolve to a private, link-local/metadata, or cluster address when Chromium navigates or follows a redirect. The browser connection performs its own resolution, so the prior Web resolution is not a binding.
-
The raw-render endpoint trusts network location alone. browser-gateway is ClusterIP-only but /api/render has no caller authentication or network policy. Any workload able to reach the Service can request browser navigations, consume the shared 2-active/16-queued capacity, and exercise the residual SSRF surface. ClusterIP is reachability, not caller identity.
Desired outcome
- Define and enforce an SSRF boundary at the component that actually performs navigation, including initial requests and redirects after DNS resolution. Reject a target when any A/AAAA result is non-public; avoid a validation-to-connect resolution gap where practical. Add a network-level backstop appropriate to the actual egress path (the persistent stealth-browser/proxy), including cloud metadata and cluster ranges.
- Restrict gateway callers to the known workloads rather than every in-cluster Pod. Inventory existing
/api/scrape and /api/render callers before choosing the smallest compatible mechanism (for example, namespace/Pod NetworkPolicy plus authenticated service-to-service identity where required).
- Preserve the documented raw-render and scrape contracts for authorised callers.
Acceptance checks
- Test a hostname whose DNS answer changes from public to blocked between validation and navigation/redirect; no browser request reaches the blocked address.
- Test representative literal IPv4/IPv6, cluster-local, metadata, and redirect cases.
- Prove an unauthorised Pod cannot invoke the gateway, while Web and all documented existing callers still can.
- Document the resulting trust and egress boundary, including operational dependencies.
Context
Guion Web sends explicit
render=browserrequests to the in-cluster browser-gatewayPOST /api/renderendpoint. The web process DNS-resolves the initial requested host and rejects private/reserved results. Gateway also rejects literal private, reserved, and cluster-local hostnames at input and on browser document redirects.Security debt
DNS rebinding / DNS TOCTOU remains possible. Gateway validation is lexical (
URL.hostname) and does not resolve a hostname. A hostile hostname can resolve to a public address during Web's initial check, then resolve to a private, link-local/metadata, or cluster address when Chromium navigates or follows a redirect. The browser connection performs its own resolution, so the prior Web resolution is not a binding.The raw-render endpoint trusts network location alone.
browser-gatewayis ClusterIP-only but/api/renderhas no caller authentication or network policy. Any workload able to reach the Service can request browser navigations, consume the shared 2-active/16-queued capacity, and exercise the residual SSRF surface. ClusterIP is reachability, not caller identity.Desired outcome
/api/scrapeand/api/rendercallers before choosing the smallest compatible mechanism (for example, namespace/Pod NetworkPolicy plus authenticated service-to-service identity where required).Acceptance checks