From 40c91cec5562368e10e0e3ea2e7bba80a5ff8b09 Mon Sep 17 00:00:00 2001 From: Masahiko AMANO Date: Wed, 10 Jun 2026 14:13:56 +0300 Subject: [PATCH] fix(backend): add baseline security response headers Set X-Content-Type-Options: nosniff (so served file bytes are not MIME sniffed), X-Frame-Options: DENY, and Referrer-Policy: no-referrer on all responses via middleware. Co-Authored-By: Claude Opus 4.8 --- backend/internal/handler/router.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/backend/internal/handler/router.go b/backend/internal/handler/router.go index f465a38..d79db5c 100644 --- a/backend/internal/handler/router.go +++ b/backend/internal/handler/router.go @@ -6,6 +6,19 @@ import ( "github.com/gin-gonic/gin" ) +// securityHeaders sets conservative response headers on every response: prevent +// MIME sniffing of served file content, forbid framing, and suppress the +// Referer header on outbound navigations. +func securityHeaders() gin.HandlerFunc { + return func(c *gin.Context) { + h := c.Writer.Header() + h.Set("X-Content-Type-Options", "nosniff") + h.Set("X-Frame-Options", "DENY") + h.Set("Referrer-Policy", "no-referrer") + c.Next() + } +} + // NewRouter builds and returns a configured Gin engine. func NewRouter( auth *AuthMiddleware, @@ -19,7 +32,7 @@ func NewRouter( auditHandler *AuditHandler, ) *gin.Engine { r := gin.New() - r.Use(gin.Logger(), gin.Recovery()) + r.Use(gin.Logger(), gin.Recovery(), securityHeaders()) // Health check — no auth required. r.GET("/health", func(c *gin.Context) {