Skip to content

desktop: local service on Tailscale receives unauthenticated requests #51075

Open

Description

@eivindjonassen

Description

Desktop 2.0.16 gets stuck on "Loading" and reports "Data migration failed" when its local service listens on a non-loopback address, such as a Tailscale IP.

The desktop's onBeforeSendHeaders filter only matches http://127.0.0.1/* and http://localhost/*, so requests to the discovered service address miss the Authorization header. The exact-origin check inside the handler already limits credentials to the registered service.

Plugins

Local notification plugin. The failure is in desktop request authentication, before the migration handler runs.

OpenCode version

2.0.16, official Linux x64 Desktop AppImage.

Steps to reproduce

  1. Start the local OpenCode service bound to the machine's Tailscale IP, with authentication enabled.
  2. Launch Desktop and let it discover the registered service.
  3. Observe the loading screen, event-stream disconnects, and migration error.

Expected: Desktop authenticates to the discovered service, including on non-loopback addresses.

Screenshot and/or share link

Request evidence from the same machine:

Desktop GET /api/experimental/migration/v1: 401 Unauthorized
Authenticated GET to the same endpoint: 200 {"status":"completed"}

A local patch that expands the HTTP(S) request filter while preserving the exact-origin and trusted-renderer checks fixes loading and the startup migration check.

Operating System

Omarchy 4.0.4, Linux 7.2.5-3-omarchy, x86_64.

Terminal

Desktop app. CLI diagnostics from foot with zsh.

Activity

  1. opencodejr commented on Oct 28, 2026

    @opencodejr
    Contributor

    Thanks for the detailed report and the request evidence. Our automated environment can't run the Electron desktop app, so a maintainer with a desktop Linux setup will need to reproduce this.

    The current code matches what you describe. In packages/desktop/src/main/windows/security.ts, wireRendererHeaders registers onBeforeSendHeaders only for http://127.0.0.1/* and http://localhost/*. The desktop app will still adopt a registered service on any address (it only rewrites 0.0.0.0 to 127.0.0.1). So when that service listens on a Tailscale or other non-loopback IP, the window's requests never reach the handler that adds the Authorization header, which explains the 401 you saw on /api/experimental/migration/v1. That filter has not changed on the current main line.

    Related, for reference:

  2. TheCupcakeisalie commented on Nov 13, 2026

    @TheCupcakeisalie

    Still reproduces on 2.2.7 (official Linux x64 AppImage, Ubuntu 24.04, X11). In current builds it shows up as a "Signed out of this server — {server} no longer accepts this app's sign-in" screen instead of the loading/migration error, so I'm noting the new wording in case it helps others find this issue.

    Setup: ~/.config/opencode/service.json sets hostname to the machine's Tailscale IP, so other devices on the tailnet can share the service. The desktop app adopts that service (v2 CLI background service ready … probed: true), then every renderer call to /api/info, /api/event, /api/config and /api/experimental/migration/v1 gets a 401. Capturing the renderer's traffic over CDP showed no Authorization header on those requests. The same endpoint returns 200 with Basic opencode:<password>.

    Widening the onBeforeSendHeaders URL filter in the shipped app.asar fixes it right away. The exact-origin and top-level-renderer checks in the handler keep the credential scoped to the service. #60525 looks like the right fix. It would be great to get it reviewed, since #51076 was auto-closed for age.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions