[BUG] Browser pane still blocks same-origin subresources on DDEV's *.ddev.site (public DNS → 127.0.0.1) after #86362 fix; *.test works

Status Open
Maintainer reply None cached
Activity 1 comment · opened Sep 17, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Not a duplicate of #86362: that issue was closed as completed on 2026-09-15; this reproduces on 2.110.1, built 2026-09-17.

In the Claude Desktop Browser pane (Code tab), a page served from a DDEV project's default hostname, https://<project>.ddev.site, loads, but every request the page makes to a local origin fails with net::ERR_BLOCKED_BY_CLIENT, including same-origin requests. Requests from the same page to a public CDN succeed.

*.ddev.site is a public wildcard DNS record pointing at 127.0.0.1. It is the default hostname for every DDEV project, so no DDEV site renders in the pane.

The same project served under a hosts-file .test name works for same-origin requests, even though the app stores identical approvals and IP pins for both origins.

Static probe page (source in Steps to Reproduce), same DDEV project and server; only the hostname changes:

| Page | Name resolves via | Same-origin fetch | Fetch to :8026 (another local origin) | Fetch to public CDN |
|---|---|---|---|---|
| https://<project>.ddev.site/claude-probe.html | public DNS | blocked | blocked | allowed |
| Same URL, with 127.0.0.1 <project>.ddev.site in /etc/hosts, app restarted | /etc/hosts | blocked | blocked | allowed |
| https://<project>.test/claude-probe.html | /etc/hosts only | allowed (200) | blocked | allowed |

Ruled out:

  • Server, DNS, TLS: curl -skI https://<project>.ddev.site returns HTTP/2 200; getent hosts <project>.ddev.site returns 127.0.0.1; the document itself loads in the pane, and the only console error code is net::ERR_BLOCKED_BY_CLIENT.
  • Hosts file vs. DNS: adding the ddev.site name to /etc/hosts changes nothing. With both names on the same line (127.0.0.1 <project>.test <project>.ddev.site, confirmed with grep before and after the run), .test works and .ddev.site stays blocked.
  • Stored approvals: ~/.config/Claude/claude_desktop_config.json lists both origins in launchPreviewAllowedOrigins and launchPreviewPrivateNetworkReadOrigins, and pins both to 127.0.0.1 in launchPreviewPrivateNetworkReadPins.
  • Outdated build: 2.110.1 was the newest package in Anthropic's apt repository when tested.

What Should Happen?

Same-origin subresources of an approved origin should load when the origin is *.ddev.site, as they do for *.test. Both origins are in the allowed lists and pinned to the same IP.

If blocking public domains that resolve to loopback is deliberate DNS-rebinding protection, an approved and pinned origin should be exempt, or there should be a user-controlled allowlist (#75289). As it stands, the pane can't render any DDEV project on its default hostname.

Error Messages/Logs

Pane console on *.ddev.site pages (URLs not shown):
Failed to load resource: net::ERR_BLOCKED_BY_CLIENT

Probe on https://<project>.ddev.site/claude-probe.html:
{
  "href": "https://<project>.ddev.site/claude-probe.html",
  "sameOrigin": "TypeError: Failed to fetch",
  "mailpit": "TypeError: Failed to fetch",
  "publicCdn": "opaque"
}

Same URL with 127.0.0.1 <project>.ddev.site in /etc/hosts (verified with grep before and after), app fully restarted:
{
  "href": "https://<project>.ddev.site/claude-probe.html",
  "sameOrigin": "TypeError: Failed to fetch",
  "mailpit": "TypeError: Failed to fetch",
  "publicCdn": "opaque"
}

Probe on https://<project>.test/claude-probe.html:
{
  "href": "https://<project>.test/claude-probe.html",
  "sameOrigin": 200,
  "mailpit": "TypeError: Failed to fetch",
  "publicCdn": "opaque"
}

Steps to Reproduce

  1. Start any DDEV project (tested with DDEV v1.25.4). It is served at https://<project>.ddev.site, which resolves to 127.0.0.1 through public DNS; grep ddev.site /etc/hosts finds nothing.
  2. Save this as claude-probe.html in the project's docroot:
   <!doctype html>
   <meta charset="utf-8">
   <title>claude-probe</title>
   <pre id="out">running…</pre>
   <script>
   (async () => {
     const probe = async (url, opts = {}) => {
       try {
         const r = await fetch(url, { cache: 'no-store', ...opts });
         return r.type === 'opaque' ? 'opaque' : r.status;
       } catch (e) { return String(e); }
     };
     document.getElementById('out').textContent = JSON.stringify({
       href: location.href,
       sameOrigin: await probe(location.href),
       mailpit: await probe(`https://${location.hostname}:8026/`, { mode: 'no-cors' }),
       publicCdn: await probe('https://cdn.jsdelivr.net/npm/jquery@3.7.1/package.json', { mode: 'no-cors' }),
     }, null, 2);
   })();
   </script>
  1. In Claude Desktop, open a Code session and open https://<project>.ddev.site/claude-probe.html in the Browser pane. Approve the site if prompted, then read the JSON on the page.
  2. Result: sameOrigin and mailpit are TypeError: Failed to fetch (console: net::ERR_BLOCKED_BY_CLIENT); publicCdn is opaque.
  3. Control: give the project a hosts-file name. Create .ddev/config.probe.local.yaml containing additional_fqdns: ["<project>.test"] and run ddev restart (DDEV adds the /etc/hosts entry). Open https://<project>.test/claude-probe.html: sameOrigin is 200.
  4. Optional: run ddev hostname <project>.ddev.site 127.0.0.1, fully quit and relaunch Claude, and repeat step 3. It is still blocked.

mailpit probes DDEV's Mailpit on port 8026, used here as a second local origin.

Claude Model

None

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

Claude Desktop 2.110.1 (ae8d2a) 2026-09-17T03:04:01.000Z (desktop app, Browser pane)

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Other

Additional Information

  • Environment: Ubuntu 24.04.5 LTS (amd64); Claude Desktop from Anthropic's apt repository; DDEV v1.25.4 (HTTPS via the DDEV router and mkcert).
  • Earlier fix: the 1.52386.0 release notes (2026-09-10) list a fix for private-network sites loading without styles, scripts, or data in the built-in browser. It does not cover this case.
  • Platform scope: tested on Linux only. The build hash (ae8d2a) matches the macOS 2.110.1 Homebrew cask, so this is probably not Linux-specific, but that is untested.
  • Untested: whether *.test works because it has no public DNS record or because of its TLD.
  • Console attribution: console lines don't include URLs. The :8026 failure on the .test page is attributed by elimination: it is the only failing request there, and https://<project>.test:8026/ loads with its CSS as a top-level navigation.
  • Cross-origin block: the blocked request to :8026 from the working .test page matches feature request #86487. It is included for completeness, not reported here.
  • Regression status: unknown for *.ddev.site. Reporters on #86362 describe hosts-mapped domains working until mid-August 2026.
  • Related: #86362, #87472, #92698, #86487, #90539, #75289. A DDEV user warned in #86362 that a fix could leave *.ddev.site blocked: https://github.com/anthropics/claude-code/issues/86362#issuecomment-5304725126
  • Workarounds for DDEV users: add a .test name with additional_fqdns (same-origin requests work; cross-origin local requests such as a Vite dev server don't), or use Claude in Chrome.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗