package middleware import ( "html" "github.com/labstack/echo/v4" ) // SecurityHeaders sets headers that limit the blast radius of any XSS bug // that slips through. The CSP keeps script-src permissive because the Vite // bundle relies on inline + eval'd scripts; tightening it requires moving // to a nonce-based policy. func SecurityHeaders() echo.MiddlewareFunc { const csp = "default-src 'self'; " + "script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; " + "style-src 'self' 'unsafe-inline'; " + "img-src 'self' data: blob: https:; " + "media-src 'self' data: blob:; " + "font-src 'self' data:; " + "connect-src 'self' ws: wss: https:; " + "frame-src 'self' blob:; " + "worker-src 'self' blob:; " + "object-src 'none'; " + "base-uri 'self'; " + "form-action 'self'; " + "frame-ancestors 'self'" return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { h := c.Response().Header() if h.Get("Content-Security-Policy") == "" { h.Set("Content-Security-Policy", csp) } if h.Get("X-Content-Type-Options") == "" { h.Set("X-Content-Type-Options", "nosniff") } if h.Get("X-Frame-Options") == "" { h.Set("X-Frame-Options", "SAMEORIGIN") } if h.Get("Referrer-Policy") == "" { h.Set("Referrer-Policy", "strict-origin-when-cross-origin") } return next(c) } } } // SecureBaseHref escapes a base URL value for safe interpolation into a // `` attribute. baseURL is built from Host / // X-Forwarded-Host, both attacker-controllable on most reverse-proxy setups. func SecureBaseHref(s string) string { return html.EscapeString(s) }