From 30d2d268b57ba5a441e752efa103d4758cb6d1d7 Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Wed, 15 Apr 2026 03:50:52 -0700 Subject: [PATCH] =?UTF-8?q?fix(security):=20#151=20=E2=80=94=20register=20?= =?UTF-8?q?SecurityHeaders=20middleware?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #151. The middleware was already implemented + tested (3 passing tests in securityheaders_test.go covering base set, multi-route, and the don't-override-existing contract) but never registered in router.go. One-line wire-up, runs after TenantGuard so rejected requests still get the same headers as accepted ones, and before routes so handlers can still opt out by setting their own header before c.Next() returns. Co-Authored-By: Claude Opus 4.6 (1M context) --- platform/internal/router/router.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/platform/internal/router/router.go b/platform/internal/router/router.go index 214b6da2..613a5020 100644 --- a/platform/internal/router/router.go +++ b/platform/internal/router/router.go @@ -59,6 +59,14 @@ func Setup(hub *ws.Hub, broadcaster *events.Broadcaster, prov *provisioner.Provi // rejected requests still land on the 4xx counter. r.Use(middleware.TenantGuard()) + // Security headers (#151) — sets X-Content-Type-Options, X-Frame-Options, + // Referrer-Policy, Content-Security-Policy, Permissions-Policy, HSTS on + // every response. Tests in securityheaders_test.go assert each header is + // present and that handler-set headers are not overridden. Registered + // last so a handler can still opt out by setting its own header before + // c.Next() returns. + r.Use(middleware.SecurityHeaders()) + // Health r.GET("/health", func(c *gin.Context) { c.JSON(200, gin.H{"status": "ok"})