From e30123ad7314411664a693f23ed0ade498ccdaf0 Mon Sep 17 00:00:00 2001 From: OHZEKI Naoki <0h23k1.n40k1@gmail.com> Date: Mon, 2 Jun 2025 13:38:19 +0900 Subject: [PATCH] refactor(recovery): extract Authorization header masking into maskAuthorization func (#4143) * refactor(recovery): extract Authorization header masking into maskAuthorization func * test(recovery): Add a test for maskAuthorization --- recovery.go | 17 +++++++++++------ recovery_test.go | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/recovery.go b/recovery.go index b3543e42..8a077dbb 100644 --- a/recovery.go +++ b/recovery.go @@ -70,12 +70,7 @@ func CustomRecoveryWithWriter(out io.Writer, handle RecoveryFunc) HandlerFunc { stack := stack(3) httpRequest, _ := httputil.DumpRequest(c.Request, false) headers := strings.Split(string(httpRequest), "\r\n") - for idx, header := range headers { - key, _, _ := strings.Cut(header, ":") - if key == "Authorization" { - headers[idx] = key + ": *" - } - } + maskAuthorization(headers) headersToStr := strings.Join(headers, "\r\n") if brokenPipe { logger.Printf("%s\n%s%s", err, headersToStr, reset) @@ -131,6 +126,16 @@ func stack(skip int) []byte { return buf.Bytes() } +// maskAuthorization replaces any "Authorization: " header with "Authorization: *", hiding sensitive credentials. +func maskAuthorization(headers []string) { + for idx, header := range headers { + key, _, _ := strings.Cut(header, ":") + if strings.EqualFold(key, "Authorization") { + headers[idx] = key + ": *" + } + } +} + // source returns a space-trimmed slice of the n'th line. func source(lines [][]byte, n int) []byte { n-- // in stack trace, lines are 1-indexed but our array is 0-indexed diff --git a/recovery_test.go b/recovery_test.go index a6e61a97..3a36fad9 100644 --- a/recovery_test.go +++ b/recovery_test.go @@ -88,6 +88,24 @@ func TestPanicWithAbort(t *testing.T) { assert.Equal(t, http.StatusBadRequest, w.Code) } +func TestMaskAuthorization(t *testing.T) { + secret := "Bearer aaaabbbbccccddddeeeeffff" + headers := []string{ + "Host: www.example.com", + "Authorization: " + secret, + "User-Agent: curl/7.51.0", + "Accept: */*", + "Content-Type: application/json", + "Content-Length: 1", + } + maskAuthorization(headers) + + for _, h := range headers { + assert.NotContains(t, h, secret) + } + assert.Contains(t, headers, "Authorization: *") +} + func TestSource(t *testing.T) { bs := source(nil, 0) assert.Equal(t, dunnoBytes, bs)