Skip to content

[Security] Enforce DNS-pinned browser policy across redirects and subresources#252

Open
fettpl wants to merge 3 commits into
sybil-solutions:mainfrom
fettpl:p1/issue-235-browser-network-policy
Open

[Security] Enforce DNS-pinned browser policy across redirects and subresources#252
fettpl wants to merge 3 commits into
sybil-solutions:mainfrom
fettpl:p1/issue-235-browser-network-policy

Conversation

@fettpl

@fettpl fettpl commented Jul 18, 2026

Copy link
Copy Markdown

Summary

Enforce one fail-closed network policy across interactive Playwright browsing and reading mode. Every hostname is resolved and every returned IPv4/IPv6 address is classified before a connection is allowed. Public browsing remains public-only; an explicitly selected loopback page may reach loopback or public destinations, but never LAN, link-local, metadata-like, multicast, documentation, or other special-use ranges.

The final implementation is adapted to main's Playwright browser architecture. Chromium is forced through mode-specific local pinning proxies, with no implicit loopback bypass, while Playwright HTTP and WebSocket routes provide an additional preflight guard. The proxy performs the authoritative resolve-and-dial operation, connects only to the selected address, preserves the original Host and TLS SNI, and never disables certificate verification.

Closes #235

Final design

  • Extend the shared browser URL contract with typed public and loopback modes plus complete IPv4/IPv6 special-use classification, including mapped IPv4 forms and malformed or zoned IPv6 rejection.
  • Fail closed on resolver errors, timeouts, empty answers, malformed answers, mixed address classes, and any address incompatible with the page's initial mode.
  • Launch mode-specific Playwright persistent contexts with service workers blocked, QUIC disabled, non-proxied WebRTC disabled, and the implicit Chromium loopback proxy bypass removed.
  • Guard HTTP(S) and WebSocket requests in Playwright, then route HTTP, HTTPS CONNECT, and WebSocket traffic through a local proxy that resolves once per connection and dials only the approved address.
  • Retain the top-level trust mode across redirects, frames, images, scripts, fetch/XHR, EventSource, workers, downloads, service-worker attempts, and WebSockets.
  • Serialize context transitions and navigation with Effect semaphores. A trust-mode change must confirm the previous context is closed before replacement; a rejected or timed-out revocation poisons the manager and prevents a second context from launching.
  • Bind BrowserHost pages to a context generation, clear stale pages on replacement, make shutdown terminal and idempotent, and recheck terminal state after both context creation and asynchronous page creation so no page is published after stop().
  • Make reading-mode redirects consume the same policy and pin every transport connection while retaining existing byte, redirect, and timeout limits.

Validation

  • Final reviewed commit: 19859e01c03fdf961eac82eeaff0ec01da099392.
  • npm --prefix services/agent-runtime run build: passed.
  • Focused BrowserHost concurrency suite: 8/8 passed, including shutdown during context creation and page creation.
  • npm run test:integration: 30/30 passed. This includes real Playwright zero-connection coverage for redirects and browser request classes, proxy HTTP/CONNECT/WebSocket pinning, reader redirect pinning, context revocation/poisoning, and BrowserHost races.
  • Real-browser regression confirmed blocked destinations accepted zero connections, allowed public/loopback dials preserved the original host, trust-mode replacement changed context generation, and service-worker registration could not escape the policy.
  • npm --prefix frontend run check:quality: passed, including package integrity, ESLint, frontend and desktop typechecks, cycle/UI/dead-code/duplicate/dependency checks, runtime bundle, and production Next.js build.
  • Shared-contract and repository-structure gates passed. The controller typecheck/lint/knip/jscpd/depcheck/standards gate passed after installing the current frozen controller dependencies.
  • git diff --check: passed; final worktree is clean.
  • The current main frontend package has no test script, so npm --prefix frontend run test is unavailable rather than represented as passing.
  • npm --prefix frontend run desktop:dist: passed and produced the macOS DMG and ZIP.
  • The generated app was ad-hoc signed with the repository entitlements from an isolated staging path; strict deep signature verification passed before and after installation.
  • Canonical /Applications/Local Studio.app bundle identifier: org.local.studio.desktop.
  • Canonical app reinstall, Launch Services registration, and relaunch passed. The persisted embedded port returned {"ok":true} from /api/desktop-health with HTTP 200.
  • Independent P0/P1 review approved exact commit 19859e01c03fdf961eac82eeaff0ec01da099392 with no findings after inspecting address classification, fail-closed DNS behavior, proxy pinning and bypass resistance, Playwright guards, reader redirects, revocation poisoning, and shutdown races.

UI changes

No intentional visual changes. Existing browser controls select a protected public or explicit-loopback context from the entered URL, and the visible page remains bound to the active protected context generation.

Risks and rollout notes

  • Public browsing now fails closed when a destination cannot be proven public. This can surface previously silent DNS or network-policy failures as blocked navigation.
  • Explicit loopback mode grants loopback and public access only; redirects and page scripts cannot upgrade a public context or reach private-network ranges.
  • The proxy does not terminate HTTPS. TLS verification remains end to end, with the original hostname preserved for certificate validation and SNI.
  • Trust-mode replacement is deliberately conservative: failure to confirm revocation permanently blocks relaunch in that manager instance.
  • The special-use address table and Chromium request-class coverage are security-sensitive and should be extended with tests before policy changes.

@fettpl
fettpl requested a review from 0xSero as a code owner July 18, 2026 20:47
@fettpl

fettpl commented Jul 18, 2026

Copy link
Copy Markdown
Author

@0xSero PR #252 is now mergeable at independently approved exact head 19859e01c03fdf961eac82eeaff0ec01da099392. Focused browser-policy/race suites, full integration and repository gates, real Playwright coverage, and the canonical desktop distribution/reinstall/health acceptance all passed. GitHub marked both current-head fork workflows as requiring maintainer approval; please approve CI and Security when convenient.

@fettpl
fettpl force-pushed the p1/issue-235-browser-network-policy branch from 2408a6c to 7a105fe Compare July 19, 2026 00:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Security] Enforce DNS-pinned browser policy across redirects and subresources

1 participant