From 706f5f6dcc52edb91eece8911b0eda45ce1d5eca Mon Sep 17 00:00:00 2001 From: clawbot Date: Tue, 10 Mar 2026 03:17:55 -0700 Subject: [PATCH] feat: add Content-Security-Policy header for embedded web SPA Set CSP header on all SPA-served responses to provide defense-in-depth against XSS. The policy restricts scripts, styles, and all other resource types to same-origin only, matching the SPA's actual behavior (external CSS/JS files, same-origin fetch API calls, no WebSockets or external resources). --- internal/server/routes.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/internal/server/routes.go b/internal/server/routes.go index 9cc0103..a35cd67 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -16,6 +16,11 @@ import ( const routeTimeout = 60 * time.Second +// cspHeader is the Content-Security-Policy applied to the embedded web SPA. +// The SPA loads external scripts and stylesheets from the same origin only; +// all API communication uses same-origin fetch (no WebSockets). +const cspHeader = "default-src 'self'; script-src 'self'; style-src 'self'" + // SetupRoutes configures the HTTP routes and middleware. func (srv *Server) SetupRoutes() { srv.router = chi.NewRouter() @@ -133,6 +138,11 @@ func (srv *Server) setupSPA() { writer http.ResponseWriter, request *http.Request, ) { + writer.Header().Set( + "Content-Security-Policy", + cspHeader, + ) + readFS, ok := distFS.(fs.ReadFileFS) if !ok { fileServer.ServeHTTP(writer, request)