From 472e86d48c0a0bb41ece7e52d95e0e730c967fa4 Mon Sep 17 00:00:00 2001 From: varun-nominal Date: Sat, 20 Jun 2026 03:19:01 -0400 Subject: [PATCH] redact sensitive headers in HTTP debug logs (#5873) --- internal/protocols/httpp/handler_logger.go | 25 ++++++++++- .../protocols/httpp/handler_logger_test.go | 43 +++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 internal/protocols/httpp/handler_logger_test.go diff --git a/internal/protocols/httpp/handler_logger.go b/internal/protocols/httpp/handler_logger.go index 6ea59e2e..7f92ec7b 100644 --- a/internal/protocols/httpp/handler_logger.go +++ b/internal/protocols/httpp/handler_logger.go @@ -14,6 +14,28 @@ const ( maxDumpedRequestBodySize = 10 * 1024 ) +var requestHeadersToRedact = map[string]struct{}{ + "Authorization": {}, + "Cookie": {}, + "Proxy-Authorization": {}, + "Set-Cookie": {}, + "X-Api-Key": {}, + "X-Auth-Token": {}, +} + +func cloneRequestForLogging(r *http.Request) *http.Request { + clone := r.Clone(r.Context()) + clone.Header = r.Header.Clone() + + for header := range requestHeadersToRedact { + if clone.Header.Get(header) != "" { + clone.Header.Set(header, "") + } + } + + return clone +} + func dumpRequestLimited(r *http.Request) ([]byte, error) { peek, err := io.ReadAll(io.LimitReader(r.Body, maxDumpedRequestBodySize+1)) if err != nil { @@ -28,8 +50,9 @@ func dumpRequestLimited(r *http.Request) ([]byte, error) { original := r.Body r.Body = io.NopCloser(bytes.NewReader(capped)) + clone := cloneRequestForLogging(r) - dump, dumpErr := httputil.DumpRequest(r, true) + dump, dumpErr := httputil.DumpRequest(clone, true) r.Body = io.NopCloser(io.MultiReader(bytes.NewReader(peek), original)) diff --git a/internal/protocols/httpp/handler_logger_test.go b/internal/protocols/httpp/handler_logger_test.go new file mode 100644 index 00000000..56b01474 --- /dev/null +++ b/internal/protocols/httpp/handler_logger_test.go @@ -0,0 +1,43 @@ +package httpp + +import ( + "io" + "net/http" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestDumpRequestLimitedRedactsSensitiveHeaders(t *testing.T) { + req, err := http.NewRequest(http.MethodPost, "http://localhost/test", strings.NewReader("request body")) + require.NoError(t, err) + + req.Header.Set("Authorization", "Bearer secret-token") + req.Header.Set("Cookie", "session=secret-cookie") + req.Header.Set("Proxy-Authorization", "Bearer proxy-secret") + req.Header.Set("X-Api-Key", "secret-api-key") + req.Header.Set("X-Auth-Token", "secret-auth-token") + + dump, err := dumpRequestLimited(req) + require.NoError(t, err) + + dumpStr := string(dump) + require.Contains(t, dumpStr, "Authorization: ") + require.Contains(t, dumpStr, "Cookie: ") + require.Contains(t, dumpStr, "Proxy-Authorization: ") + require.Contains(t, dumpStr, "X-Api-Key: ") + require.Contains(t, dumpStr, "X-Auth-Token: ") + require.NotContains(t, dumpStr, "secret-token") + require.NotContains(t, dumpStr, "secret-cookie") + require.NotContains(t, dumpStr, "proxy-secret") + require.NotContains(t, dumpStr, "secret-api-key") + require.NotContains(t, dumpStr, "secret-auth-token") + require.Contains(t, dumpStr, "request body") + + require.Equal(t, "Bearer secret-token", req.Header.Get("Authorization")) + + body, err := io.ReadAll(req.Body) + require.NoError(t, err) + require.Equal(t, "request body", string(body)) +}