From 9ae2cca8017618b618f004aa90f77f1e8c4ccb7e Mon Sep 17 00:00:00 2001 From: Mike Teehan Date: Wed, 12 Aug 2026 19:18:28 +0000 Subject: [PATCH] fix: clean up lazy import, dead var, whitespace; document WS session caveat - Move get_all_credential_counts import to top-level in daemon/handlers/auth.py - Remove unused PROJECT_DIR in scripts/bootstrap_auth.py - Fix leading space in api.js tryRefreshToken function - Document WebSocket session binding limitation in docs/security.md --- daemon/handlers/auth.py | 3 +-- docs/security.md | 2 ++ scripts/bootstrap_auth.py | 1 - webui/static/hoover/api.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/daemon/handlers/auth.py b/daemon/handlers/auth.py index 0cfb306..5a0e27c 100644 --- a/daemon/handlers/auth.py +++ b/daemon/handlers/auth.py @@ -56,6 +56,7 @@ from lib.auth_users import ( from lib.webauthn import ( create_authentication_options, create_registration_options, + get_all_credential_counts, get_management_domains, get_rp_name, list_credentials, @@ -595,6 +596,4 @@ def webauthn_remove_credential(request: Any, body: Any) -> dict[str, Any]: @registry.register(GET_AUTH_WEBAUTHN_CREDENTIAL_COUNTS) def webauthn_credential_counts(_request: Any, body: Any) -> dict[str, int]: """Return credential counts for all users (admin endpoint).""" - from lib.webauthn import get_all_credential_counts - return get_all_credential_counts() diff --git a/docs/security.md b/docs/security.md index bec887b..7d0ac85 100644 --- a/docs/security.md +++ b/docs/security.md @@ -104,6 +104,8 @@ Token theft protection: - Token blacklist prevents reuse after logout or password change - XSS mitigations: CSP headers, `X-XSS-Protection` header on management domain +**WebSocket session binding limitation**: WebSocket connections skip `session_id` validation. Browsers cannot send custom headers during the WebSocket handshake — the token is passed via the `Sec-WebSocket-Protocol` subprotocol or an nginx-injected `X-Auth-Token` header. This means a stolen access token can be used to open WebSocket connections for the full 15-minute TTL without session verification. Short-lived TTL and management domain CSP headers mitigate this risk. + ### WebAuthn Security WebAuthn (passkeys) provides passwordless authentication via the browser's Web Authentication API. Security properties: diff --git a/scripts/bootstrap_auth.py b/scripts/bootstrap_auth.py index 70c47b4..0fbc1f5 100644 --- a/scripts/bootstrap_auth.py +++ b/scripts/bootstrap_auth.py @@ -17,7 +17,6 @@ import sys from pathlib import Path # Ensure project lib is importable -PROJECT_DIR = Path(".") def main() -> None: diff --git a/webui/static/hoover/api.js b/webui/static/hoover/api.js index 2c1c0f5..1d487b9 100644 --- a/webui/static/hoover/api.js +++ b/webui/static/hoover/api.js @@ -83,7 +83,7 @@ let _refreshPromise = null; * * @returns {Promise} ``true`` if refresh succeeded */ - async function tryRefreshToken() { +async function tryRefreshToken() { if (!_refreshPromise) { _refreshPromise = (async () => { try {