Skip to content

Inbox refuses all reverse-proxy requests: x-forwarded-for treated as tailnet exposure (breaks local proxies) #1867

Closed

Description

@solalbaudoincs

What happened

Since the 0.28.9+ security hardening ("hostname check on every server" / tailnet detection), the Inbox's localOnly check treats any request carrying an x-forwarded-for header as tailnet exposure and refuses it:

var SERVE_HEADERS = ["tailscale-headers-info", "tailscale-user-login", "x-forwarded-for"];
// ...
if (SERVE_HEADERS.some((name) => req.headers.has(name))) {
  tailscale.noteServedRequest();
  return Promise.resolve(localOnly());
}

Response: {"error":"This answers only on this computer, not over the tailnet.","code":"local_only"} (403).

Why this is a problem

Every reverse proxy adds x-forwarded-for — it's standard proxy behavior, not a Tailscale signature. A purely local proxy chain (loopback → local HTTPS front-end → loopback inbox) gets 403'd even though the request never left the machine. This breaks:

  • local HTTPS front-ends with named domains (e.g. portless .localhost aliases — my case: inbox.localhost → 127.0.0.1:<port>)
  • nginx/caddy local setups
  • any dev server proxying to the inbox

Verified by sending x-forwarded-for: 1.2.3.4 on an otherwise plain loopback request — 403 local_only; without the header, 200.

Suggested fix

The two tailscale-* headers are genuinely Tailscale-serve-specific and are the right signal. x-forwarded-for alone is not — it only becomes meaningful when tailscale serve is the thing adding it. Options:

  1. Drop x-forwarded-for from SERVE_HEADERS (the Host-header guard already protects loopback-only endpoints).
  2. Only treat x-forwarded-for as tailnet-exposure when tailscale is actually publishing (the inbox already tracks tailnetPublished state).
  3. Check that x-forwarded-for's value is a non-loopback address (tailscale serve forwards the real client IP; a local proxy forwards 127.0.0.1).

Workaround in the meantime

A tiny local proxy that strips x-forwarded-for (and the other forwarded headers) in front of the inbox.

Versions: plannotator 0.28.16 (darwin-arm64), inbox started via plannotator inbox --background.

Activity

  1. added
    bugSomething isn't working
    triageIssue created from backlog triage
    on Oct 21, 2026
  2. added a commit that references this issue on Oct 22, 2026
  3. backnotprop commented on Oct 22, 2026

    @backnotprop
    Owner

    Fixed in #2060.

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

    bugSomething isn't workingtriageIssue created from backlog triage

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions