← Back to list
01Issue
BugOpenSwamp CLIPublic
AssigneesNone
Relationships
#3892 WS handshake drops the port from the Origin, so a --trusted-hosts entry with a port never matches (follow-up to #1840)
Opened by thomas · 10/24/2026
Situation
I publish swamp serve --dashboard on my tailnet with tailscale serve, which terminates TLS and forwards to serve on loopback. Tailscale gives each machine a single HTTPS hostname, and port 443 on that name already serves something else, so the dashboard has to be published on another port. The public address is https://swamp.example.ts.net:9443, and the browser sends Origin: https://swamp.example.ts.net:9443.
No single --trusted-hosts entry lets the dashboard both sign in and open its WebSocket:
--trusted-hosts swamp.example.ts.net:9443: sign-in succeeds, then every WebSocket upgrade is rejected:WebSocket upgrade rejected: "untrusted origin: https://swamp.example.ts.net:9443"--trusted-hosts swamp.example.ts.net: the WebSocket would pass, but sign-in is rejected:Dashboard session request rejected: "origin does not match request authority: https://swamp.example.ts.net:9443"- Workaround: list both,
--trusted-hosts swamp.example.ts.net,swamp.example.ts.net:9443.
Setup
tailscale serve --bg --https=9443 http://127.0.0.1:9090
swamp serve --host 127.0.0.1 --port 9090 --auth-mode oauth --admins <me> --allowed-users <me> \
--dashboard --trusted-hosts <one of the values above>Reproduction without a tailnet or OAuth
swamp serve --port 19090 --auth-mode token --admins user:repro --dashboard --no-schedule \
--trusted-hosts swamp.example.ts.net:9443
O=https://swamp.example.ts.net:9443; H=swamp.example.ts.net:9443
# WebSocket upgrade
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:19090/ -H "Host: $H" -H "Origin: $O" \
-H 'Connection: Upgrade' -H 'Upgrade: websocket' -H 'Sec-WebSocket-Version: 13' \
-H 'Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ=='
# Dashboard session
curl -s -o /dev/null -w '%{http_code}\n' -X POST http://127.0.0.1:19090/auth/dashboard/session \
-H "Host: $H" -H "Origin: $O" -H 'content-type: application/json' -d '{}'--trusted-hosts |
WebSocket upgrade | Dashboard session |
|---|---|---|
swamp.example.ts.net:9443 |
403, untrusted origin |
passes the origin check (400, empty body) |
swamp.example.ts.net |
passes the origin check (401, no token) | 403, origin does not match request authority |
| both | passes (401) | passes (400) |
Cause
The two checks treat the port differently:
- The WebSocket check (
validateOrigin/trustedOrigins, from #1840) cuts the Origin down toprotocol//hostnamebefore comparing it withhttps://<entry>. An entry with a port can never match, and an Origin with a port matches only an entry without one. - The dashboard check (
validateDashboardSessionOrigin) compares the full origin, port included, withhttps://<entry>. A bare-hostname entry matches only port 443.
Version
20261024.204655.0
Suggested fixes
- Make both checks treat the port the same way. For example, keep the port in the WebSocket check's
originBaseso that ahost:portentry works for both checks. A bare-hostname entry would then still mean port 443, as it already does in the dashboard check. - Or document how to write
--trusted-hostsentries for a port other than 443. - Alternatively, bring back the
--trusted-originssetting proposed in #1840, so the exact browser origin (https://host:9443) can be given.
02Bog Flow
Open
No activity in this phase yet.
03Sludge Pulse
Sign in to post a ripple.