soulsync/core/security
BoulderBadgeDad 46eccbb237 #852: gate the WebSocket handshake — close the launch-PIN/login bypass
The #832 fix enforces the launch PIN / login via a Flask before_request hook, but
that hook does NOT run for the socketio handshake — empirically a normal endpoint
401s while /socket.io/ returns 200 with the gate on. So removing the client overlay
(Safari "Hide Distracting Items", devtools) + opening a socket streams live data
(downloads, logs, dashboard, notifications) completely unauthenticated.

Fix: the socketio connect handler now enforces the same check and returns False
(rejects the connection) when a gate is active and the session isn't verified.
Rejecting connect blocks every downstream WS event (subscribe/join), so all live
data is covered. core/security/ws_gate.is_ws_connection_blocked is the pure seam:
login mode (when on) > launch PIN > open, mirroring the HTTP gate exactly. Fails
OPEN on a config-read error, same as the HTTP gate.

Audited every other surface empirically with the gate on + unauthenticated: SSE
streams, catch-all pages, library/dashboard data, admin endpoints, search,
image-proxy, audio-stream (incl. a /etc/passwd traversal probe) all 401; /api/v1
key-gated. The WebSocket was the only hole.

Tests (10): pure gate logic (login>pin precedence, all on/off combos) + real
socketio.test_client integration — connect rejected when gate on + unauthenticated,
allowed when gate off or PIN verified.
2026-06-11 13:27:03 -07:00
..
__init__.py Security: enforce the launch PIN server-side, not just a client overlay (#832) 2026-06-09 22:19:14 -07:00
auth_proxy.py Security: trust a forward-auth proxy user header (Tier 3) 2026-06-10 20:57:48 -07:00
launch_lock.py Fix: launch PIN re-triggered the first-run setup wizard every visit (#842) 2026-06-10 11:40:47 -07:00
login_gate.py Login recovery (DB + backend): security question to reset a forgotten password 2026-06-10 22:24:54 -07:00
rate_limit.py Security: brute-force limiter on the launch-PIN unlock (Tier 2) 2026-06-10 20:47:46 -07:00
reverse_proxy.py Security: add gated security headers in reverse-proxy mode (Tier 2) 2026-06-10 20:48:51 -07:00
ws_gate.py #852: gate the WebSocket handshake — close the launch-PIN/login bypass 2026-06-11 13:27:03 -07:00