From 4430ce38a4046c74cbeacf50ce03991ddd7012fc Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Mon, 30 Mar 2026 17:43:53 -0700 Subject: [PATCH] Allow htmx swap styles in CSP Add 'unsafe-hashes' with the htmx swap indicator style hash to the style-src CSP directive. Without this, htmx swap transitions are blocked by CSP, which can prevent HX-Redirect from being processed on the SSO login flow. Security: - Uses 'unsafe-hashes' (not 'unsafe-inline') so only the specific htmx style hash is permitted, not arbitrary inline styles Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/ui/ui.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/ui/ui.go b/internal/ui/ui.go index 855d3d4..2afb558 100644 --- a/internal/ui/ui.go +++ b/internal/ui/ui.go @@ -749,8 +749,11 @@ func noDirListing(next http.Handler) http.Handler { func securityHeaders(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { h := w.Header() + // Security: 'unsafe-hashes' with the htmx swap indicator style hash + // allows htmx to apply its settling/swapping CSS transitions without + // opening the door to arbitrary inline styles. h.Set("Content-Security-Policy", - "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'") + "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-hashes' 'sha256-bsV5JivYxvGywDAZ22EZJKBFip65Ng9xoJVLbBg7bdo='; img-src 'self' data:; font-src 'self'") h.Set("X-Content-Type-Options", "nosniff") h.Set("X-Frame-Options", "DENY") h.Set("Strict-Transport-Security", "max-age=63072000; includeSubDomains")