fix(websockets): don't reject same-origin WS upgrades behind port-stripping proxies#269
Conversation
…ipping proxies
The Origin guard's same-origin fallback compared urlsplit(origin).netloc
against the Host header verbatim. Reverse proxies routinely forward Host
without the port -- the linuxserver baseimage that deploys Selkies does
('proxy_set_header Host $host'; nginx's $host strips it) -- while a
browser Origin carries any non-default port. A same-origin client
reaching the container via an explicit port (e.g. the '-p 3001:3001'
mapping in linuxserver's docs, or any remapped port) was therefore 403'd
in a reconnect loop; only default-port (443/80) deployments worked.
When the forwarded Host carries no port to compare, fall back to
comparing hostnames. A Host that does include a port still requires an
exact netloc match, and cross-site Origins remain rejected either way.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request modifies the WebSocket origin validation in src/selkies/stream_server.py to handle scenarios where reverse proxies forward the Host header without a port, while the browser's Origin header contains a non-default port. It now falls back to comparing hostnames when the forwarded Host does not specify a port. There are no review comments, so I have no feedback to provide.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
155eb0b to
de77558
Compare
|
Fixes incorporated in de77558, linuxserver/pixelflux@b32a178, linuxserver/pcmflux@0cbadcb. |
3bab531 to
4de4c8a
Compare
_is_ws_origin_allowedcompares theOriginheader against the forwardedHost. Behind a reverse proxy configured withproxy_set_header Host $host(nginx$hoststrips the port — this is what linuxserver.io's bundled config does), the browser'sOrigincarries an explicit port (e.g.https://example.com:3001) while the forwardedHosthas none, so the exact string comparison fails and every same-origin websocket upgrade is rejected — with no hint client-side, since the 403 happens before the upgrade.Fix: when the forwarded
Hostcarries no port, fall back to comparing hostnames only. Exact host:port matching is preserved whenever the proxy forwards a port. Checked against IPv6 literals,Origin: null, and genuine cross-site origins (still rejected).Found and tested while second-eye testing #254 on an lsio-based image (their nginx proxies the websocket with
Host $hoston port 3001).🤖 Generated with Claude Code