From b5b9df01a43bcb8454273c1044b6846d6d39adc7 Mon Sep 17 00:00:00 2001 From: Arthur Breitman Date: Thu, 18 Jun 2026 12:32:15 +0000 Subject: [PATCH 1/4] fix(web): plumb CSRF token to admin templates so POST forms work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every POST form on the admin web UI (Add GitLab connection, Add LLM, Rotate passphrase, Create token, etc.) was failing at the middleware with "csrf token missing or invalid". The templates didn't emit a csrf_token form field and the render path didn't expose the plaintext token to the page. The middleware only had the SHA-256 hash from Lookup(), and the plaintext from Issue() was thrown away after the session cookie was set. Fix: - session: set a NON-HttpOnly sieve_csrf cookie at Issue time carrying the plaintext token (HttpOnly off is the documented synchronizer- token pattern — the page script needs to read it). SameSite=Lax to match the session cookie so OAuth callback flows still receive both. /logout clears the cookie alongside the session cookie. - web/auth.go: login + setup handlers SetCookie the new sieve_csrf alongside sieve_session. The requireOperatorSession middleware reads the sieve_csrf cookie and stashes the plaintext on sess.CSRFToken so handlers/templates can echo it back. Missing cookie is not fatal — the next POST fails closed and the operator re-logs in. - web/server.go: render() now injects CSRFToken into template data from the session in context. Two shapes are supported: * map[string]any: m["CSRFToken"] = token (when absent). * *struct or struct with a string field named CSRFToken: set via reflection (when zero). connectionEditData declares the field to opt in. - web/templates/nav.html: a single inline