Skip to content

[Bug]: Preview address bar rewrites localhost URLs to WSL IP, breaking loopback-only and HTTPS servers #3938

Description

@Chrrxs

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/desktop

Steps to reproduce

  1. Run T3 Code Desktop on Windows with a WSL environment/backend selected.

  2. Inside WSL, start a server that listens only on loopback:

    python3 -m http.server 8000 --bind 127.0.0.1
  3. Confirm http://localhost:8000/ works from a normal Windows browser through WSL localhost forwarding.

  4. Open T3 Code's built-in preview browser.

  5. Enter http://localhost:8000/ or http://127.0.0.1:8000/ in the preview address bar.

  6. Repeat with an HTTPS loopback URL such as https://localhost:8000/ when using a local HTTPS development server.

Expected behavior

A URL entered in the preview address bar should retain its requested origin. In particular:

  • http://localhost:8000/ should remain http://localhost:8000/.
  • http://127.0.0.1:8000/ should remain http://127.0.0.1:8000/.
  • https://localhost:8000/ should remain https://localhost:8000/.

Environment-relative port navigation may translate hosts when explicitly requested, but manually entered direct URLs should not silently change origin.

Actual behavior

The preview address bar rewrites loopback URLs to the active WSL environment's private eth0 address before Electron loads them. On the affected machine, the current WSL address was 172.25.85.75:

http://localhost:8000/       -> http://172.25.85.75:8000/
http://127.0.0.1:8000/       -> http://172.25.85.75:8000/
https://localhost:8000/      -> https://172.25.85.75:8000/

This is a client-side URL substitution rather than an HTTP redirect: the loopback server returns 200 without a Location header, and direct navigation to localhost does not change the hostname.

A server bound only to 127.0.0.1 becomes unreachable through the substituted WSL address. HTTPS development servers can additionally fail certificate validation because a certificate for localhost does not cover the WSL IP. The origin change can also affect cookies, CORS, allowed-host checks, and OAuth callback URLs.

The behavior is deterministic in the shipped source:

  • apps/server/src/components/preview/PreviewView.tsx sends every address-bar submission through resolveDiscoveredServerUrl().
  • apps/server/src/browser/browserTargetResolver.ts turns any recognized loopback URL into an environment-port target when the environment connection host is non-loopback.
  • The environment-port resolver replaces the requested hostname with the hostname from connection.httpBaseUrl while preserving protocol, port, path, query, and hash.
  • apps/server/src/preview/PortScanner.ts normalizes both loopback-only and wildcard listeners to localhost, discarding the bind scope needed to determine whether the WSL IP is reachable.

The browser target interface already distinguishes { kind: "url" } from { kind: "environment-port" }. Address-bar submissions appear to be using the discovered/environment-port behavior even though they are direct URL requests.

Impact

Major degradation or frequent failure

Version or commit

T3 Code desktop 0.0.29-nightly.20260712.791; the same behavior was initially reproduced on 0.0.28.

Environment

Windows 10.0.26200.8655, WSL2 kernel 6.6.87.2-microsoft-standard-WSL2, Ubuntu 24.04, x86_64.

Logs or stack traces

$ hostname -I
172.25.85.75 10.0.0.4 172.19.0.1 172.17.0.1 172.18.0.1

$ curl -I http://localhost:8000/
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.12.3
# No Location header

# T3 preview environment-port resolution, changing only protocol:
protocol=http  -> http://172.25.85.75:8000/
protocol=https -> https://172.25.85.75:8000/

Screenshots, recordings, or supporting files

No attachment. The final URL shown in the preview address bar and the deterministic resolver behavior above capture the failure.

Workaround

Open the original localhost URL in a normal Windows browser.

For HTTP-only development, binding the server to 0.0.0.0 can make it reachable through the substituted WSL IP, but this broadens exposure and does not solve HTTPS origin/certificate problems.

A focused product fix would treat address-bar submissions as direct { kind: "url" } navigation and reserve { kind: "environment-port" } translation for discovered local-server cards or other explicitly environment-relative navigation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions