Conversation
|
Hi @sdogruyol, Thanks for the fast turnaround. I pulled Spec suite (fix/cswsh): Confirms all scenarios described in the PR (same-origin, TLS-terminated proxy, port mismatch, allowlist match, wildcard, missing/empty/null Origin) are covered by automated tests with no regressions — routing behavior is unaffected too. Before/after comparison, same cross-origin request ( On Confirms the vulnerability is real — the handshake completes and the socket is hijackable. On Confirms the fix closes it. Additional manual verification on Missing Origin -> rejected: Same-origin Origin -> accepted:
Old allow-all behavior still available as an explicit opt-in.
Explicit allowlist behaves as documented. Everything matches the PR description exactly. This closes the CSWSH gap — default is now secure, and same-origin/allowlist/wildcard all work as expected. One question for discussion (not a blocker): the same-origin check trusts the request's Thanks again for closing the gap so quickly. 🙏 |
Summary
This PR fixes Cross-Site WebSocket Hijacking (CSWSH) by making WebSocket
Originvalidation secure by default.Previously, an empty
Kemal.config.websocket_allowed_origins(the default) accepted all origins. A malicious site could open a WebSocket to a Kemal app from a victim’s browser; cookies were still sent with the handshake, so cookie-authenticated sockets were exposed.New behavior
websocket_allowed_origins[](default)Originmust match the requestHost. Missing/empty/nullOrigin →403 Forbidden.403."*"Origin(curl/wscat/native clients).Same-origin matching uses the scheme from
Originand the host/port fromHost. That way TLS termination in front of Kemal still works (Origin: https://app.example.com+Host: app.example.comsucceeds even when Kemal itself is plain HTTP).No Config property type changes.
normalize_websocket_origin/reject_websocket_forbidden!are unchanged in role; same-origin logic lives next to the existing allowlist check inWebSocketHandler.Alternate Designs
Kemal.config.scheme+Host— Rejected. Under a reverse-proxy TLS terminatorconfig.schemeis usually"http"while the browser sendshttps://…, causing false403s for legitimate same-site clients."*"escape hatch — Matches Action Cable / Phoenix / Spring posture, keeps same-origin browser apps working, and gives a one-line rollback for non-browser clients.Benefits
Origin, authority fromHost).Originuse["*"].CHANGELOG(Unreleased).Possible Drawbacks
403for:Origin(curl, wscat, many native clients).websocket_allowed_originsto the real origins, or["*"]if the old open policy is intentional.Origin. Authentication on the socket remains necessary.