Fix WebSocket CSRF validation failure on Chromium browsers over HTTPS

SameSite=Strict cookies are not sent with WebSocket upgrade requests on Chromium-based browsers (Brave confirmed), causing the CSRF cookie check at connect time to fail with 'csrf cookie mismatch'. This breaks the state_sync namespace, preventing the UI from loading chats. Change SameSite from Strict to Lax for both the Flask session cookie and the JavaScript-set CSRF token cookie. Lax still prevents cross-site POST CSRF while allowing same-origin WebSocket upgrades to include cookies. Fixes #1237

Paolo Calvi committed Mar 11, 2026 at 00:00 UTC 07f94ef4b5d79834df6164d7b04176062114c599
2 files changed +2 -2
run_ui.py
+1 -1
@@ -52,7 +52,7 @@ WerkzeugRequest.max_form_memory_size = UPLOAD_LIMIT_BYTES
52 webapp.config.update(
53 JSON_SORT_KEYS=False,
54 SESSION_COOKIE_NAME="session_" + runtime.get_runtime_id(), # bind the session cookie name to runtime id to prevent session collision on same host
55 - SESSION_COOKIE_SAMESITE="Strict",
55 + SESSION_COOKIE_SAMESITE="Lax",
56 SESSION_PERMANENT=True,
57 PERMANENT_SESSION_LIFETIME=timedelta(days=1),
58 MAX_CONTENT_LENGTH=int(os.getenv("FLASK_MAX_CONTENT_LENGTH", str(UPLOAD_LIMIT_BYTES))),
webui/js/api.js
+1 -1
@@ -219,7 +219,7 @@ export async function getCsrfToken() {
219 if (cookieRuntimeId) {
220 const _secureFlag =
221 window.location.protocol === "https:" ? "; Secure" : "";
222 - document.cookie = `csrf_token_${cookieRuntimeId}=${csrfToken}; SameSite=Strict; Path=/${_secureFlag}`;
222 + document.cookie = `csrf_token_${cookieRuntimeId}=${csrfToken}; SameSite=Lax; Path=/${_secureFlag}`;
223 } else {
224 console.warn("CSRF runtime id missing; skipping cookie name binding.");
225 }