From e320f95d9f8d42f185195e9419ea4e1a3f55984a Mon Sep 17 00:00:00 2001 From: Thijs Herman <64640608+Turbootzz@users.noreply.github.com> Date: Fri, 20 Feb 2026 12:39:04 +0100 Subject: [PATCH] Security: Redact secret names from production logs & bind port to localhost (#1) * security: redact secret names from logs, bind port to localhost - handlers: replace secret names in Warn/Error logs with client IP (prevents information disclosure via log access/injection) - client: downgrade secret name logs from Info to Debug level (Debug is discarded in production via io.Discard) - docker-compose: bind port to 127.0.0.1:8080 instead of 0.0.0.0:8080 (prevents direct access bypassing reverse proxy) Found during security pen test of vault.turboot.com * Enhance logging for secret retrieval and cache access --- docker-compose.yml | 2 +- internal/handlers/handlers.go | 4 ++-- internal/vaultwarden/client.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index b738e4c..9517752 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: container_name: vaultwarden-api restart: unless-stopped ports: - - "8080:8080" + - "127.0.0.1:8080:8080" environment: # Server configuration - API_PORT=8080 diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index 0cc1fee..02eb3c5 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -40,7 +40,7 @@ func (h *Handler) GetSecret(c *fiber.Ctx) error { } if !validators.IsValidSecretName(secretName) { - logger.Warn.Printf("Invalid secret name attempted: %s", secretName) + logger.Warn.Printf("Invalid secret name format attempted from IP: %s", c.IP()) return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ "error": "invalid secret name format", }) @@ -48,7 +48,7 @@ func (h *Handler) GetSecret(c *fiber.Ctx) error { value, err := h.vaultClient.GetSecret(secretName) if err != nil { - logger.Error.Printf("Failed to fetch secret '%s': %v", secretName, err) + logger.Error.Printf("Failed to fetch secret (requested by IP: %s): %v", c.IP(), err) return c.Status(fiber.StatusNotFound).JSON(fiber.Map{ "error": "secret not found", }) diff --git a/internal/vaultwarden/client.go b/internal/vaultwarden/client.go index d5179f5..ec7bb6f 100644 --- a/internal/vaultwarden/client.go +++ b/internal/vaultwarden/client.go @@ -59,13 +59,13 @@ func (c *Client) GetSecret(name string) (string, error) { // Check cache first if c.cache.enabled { if value, found := c.cache.get(name); found { - logger.Info.Printf("Cache hit for secret: %s", name) + logger.Debug.Printf("Cache hit for secret") return value, nil } } // Cache miss - fetch from API - logger.Info.Printf("Fetching secret from Vaultwarden: %s", name) + logger.Debug.Printf("Fetching secret from Vaultwarden (cache miss)") value, err := c.fetchSecret(name) if err != nil { return "", err