Desktop Browser pane: allow user-approved local hostnames (hosts-file aliases) as trusted preview origins — currently all subresources blocked with ERR_BLOCKED_BY_CLIENT

Status Closed — duplicate
Reported on v2.1.227
Maintainer reply None cached
Activity 3 comments · opened Aug 12, 2026 · closed Aug 15, 2026

Feature request

Let the user explicitly approve a custom local hostname (a hosts-file alias for 127.0.0.1) as a trusted preview origin in the desktop app's Browser pane — the same way per-origin approval already exists for top-level navigation.

Environment

  • Claude Desktop 1.28929.0 (Windows 10, MSIX), Claude Code CLI 2.1.227
  • Dev server: Nuxt over HTTPS (mkcert cert) at https://local.cr8s.com:3000, where local.cr8s.com is a hosts-file entry for 127.0.0.1
  • .claude/launch.json entry with "port": 3000, "url": "https://local.cr8s.com:3000"

Current behavior

Top-level document navigations to https://local.cr8s.com:3000 work (approval flow), but every subresource — scripts, CSS, images, same-origin fetch/XHR — fails with net::ERR_BLOCKED_BY_CLIENT. The page renders as bare SSR HTML with no hydration, making the preview unusable for that origin.

From tracing the behavior (and the launch-preview:before-request handler's log strings), this appears deliberate: subresource requests from a non-preview-origin page to a host that resolves to loopback/private space are cancelled ("Blocked subresource to private-resolving host"). Literal localhost / *.localhost / 127.0.0.1 / ::1 page origins are trusted and work fine. This matches the desktop docs, which enumerate exactly those hostnames as opening directly.

Observed matrix (same server, same mkcert cert):

| Page origin | Target | Result |
|---|---|---|
| https://localhost:3000 | anything (same-origin, other loopback names, public hosts) | ✅ allowed |
| https://local.cr8s.com:3000 | same-origin subresources | ❌ ERR_BLOCKED_BY_CLIENT |
| https://local.cr8s.com:3000 | localhost:<any port>, 127.0.0.1 | ❌ ERR_BLOCKED_BY_CLIENT |
| https://local.cr8s.com:3000 | public hosts (e.g. our production API) | ✅ allowed |

Also confirmed: the launch.json url field opens the tab there but grants the origin no subresource trust, and there is no settings/launch.json/org-policy knob to extend the trusted list.

Why this matters

The hosts-file-alias pattern is standard for local development whenever cookie domains are involved — it's a big part of why mkcert exists. Our app's session cookie is Domain=<apex>.com-scoped, so a *.<apex>.com dev hostname is the only way to test any logged-in behavior locally. localhost cannot hold the cookie by spec (and SameSite=Lax blocks it on cross-site API calls from a localhost page), so the current allowlist limits the Browser pane to logged-out surfaces only. We've had to move logged-in verification out of the pane entirely (Playwright).

We understand the security intent — an unrestricted hosts-file alias is indistinguishable from a malicious public page probing the local network (DNS rebinding). We're not asking for the gate to be removed.

Proposed solution

An explicit, user-visible opt-in, e.g. any of:

  1. An approval card when a user-navigated origin's subresources would be blocked as private-resolving — "This site resolves to your local machine. Trust it as a dev server?" — scoped per origin, like existing navigation approval.
  2. A .claude/launch.json field (e.g. "trustedHostnames": ["local.cr8s.com"]) that registers the hostname as a preview origin for a configured server, so trust is a deliberate, repo-visible choice.
  3. A desktop settings allowlist for local dev hostnames.

Option 2 feels most in keeping with the existing model: launch.json already ties a named server to a port; letting it also name the hostname the developer actually serves on would make url + trust consistent.

Workarounds we're using

  • https://localhost:3000 in the pane for logged-out testing (works fully).
  • Playwright (own browser context) against the aliased hostname for logged-in flows.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗