fix(web_server): propagate --insecure flag to WebSocket security checks#31772
Closed
pranvgarg wants to merge 1 commit into
Closed
fix(web_server): propagate --insecure flag to WebSocket security checks#31772pranvgarg wants to merge 1 commit into
pranvgarg wants to merge 1 commit into
Conversation
start_server() stored allow_public in a local variable but never wrote it to app.state, so every getattr(app.state, "insecure", False) call in the security guards always evaluated to False — making the --insecure flag a no-op for WebSocket connections. Symptoms: when the dashboard is bound to a non-loopback address via --insecure (e.g. a Tailscale IP), all WebSocket upgrades to /api/pty, /api/ws, /api/pub, and /api/events were rejected with 403 because _ws_client_is_allowed() saw a non-loopback peer IP and returned False. HTTP endpoints worked fine because _is_accepted_host() matched the bound host directly. Fix: - Set app.state.insecure = allow_public in start_server() so the flag is visible to all request handlers at runtime. - Add the corresponding insecure short-circuit to _ws_client_is_allowed() and _ws_host_origin_is_allowed(), consistent with the existing guard in host_header_middleware. - Correct host_header_middleware's insecure branch to return await call_next(request) instead of bare True (returning a non-Response from ASGI middleware causes a runtime error). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Author
|
Closing to revise — will reopen with a cleaner version. |
This was referenced May 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When the dashboard is bound to a non-loopback address using
--insecure(e.g. a Tailscale IP like100.116.24.10), all WebSocket connections to/api/pty,/api/ws,/api/pub, and/api/eventsfail with 403 Forbidden.HTTP endpoints work fine. Only WebSockets are broken.
Root cause
start_server()acceptsallow_public: bool(set when--insecureis passed) and uses it to skip the startupSystemExitguard — but never writes it toapp.state:Every
getattr(app.state, "insecure", False)call in the security guards always evaluates toFalse, making--insecurea no-op for WebSocket connections.Specifically,
_ws_client_is_allowed()checks the peer IP against_LOOPBACK_HOSTS. When the server is bound to a non-loopback address, the connecting client also has a non-loopback IP — so the check always fails and the WebSocket is rejected.Fix
app.state.insecure = allow_publicinstart_server()so the flag is visible to all handlers at runtime.insecureshort-circuit to_ws_client_is_allowed()and_ws_host_origin_is_allowed(), consistent with the existing (but unreachable) guard already present inhost_header_middleware.host_header_middleware's insecure branch toreturn await call_next(request)instead of bareTrue— returning a non-Responsefrom an ASGI middleware causes a runtimeTypeError.Verification
Tested with
hermes dashboard --host <tailscale-ip> --insecure. Before this fix,/api/eventsand/api/ptyboth returned 403. After this fix, both WebSocket connections complete the handshake and the dashboard chat tab works correctly.