diff --git a/internal/logs/sanitizer.go b/internal/logs/sanitizer.go index ca66dae64..24dacba8d 100644 --- a/internal/logs/sanitizer.go +++ b/internal/logs/sanitizer.go @@ -114,6 +114,9 @@ func (s *SecretSanitizer) registerDefaultPatterns() { if len(parts) != 3 { return "****" } + if len(parts[2]) < 4 { + return parts[0] + ".***.***" + } // Show first part (header) but mask payload and signature return parts[0] + ".***." + parts[2][len(parts[2])-4:] }, diff --git a/internal/logs/sanitizer_jwt_short_signature_test.go b/internal/logs/sanitizer_jwt_short_signature_test.go new file mode 100644 index 000000000..f3ce9304e --- /dev/null +++ b/internal/logs/sanitizer_jwt_short_signature_test.go @@ -0,0 +1,28 @@ +package logs + +import ( + "strings" + "testing" +) + +// The jwt regex accepts a 1-3 character signature segment; masking it must +// not slice out of range (a panic inside the zap core takes the caller down). +func TestSanitizer_JWTShortSignatureDoesNotPanic(t *testing.T) { + s := newTestSanitizer() + const payload = "eyJzdWIiOiIxIn0" + for _, sig := range []string{"x", "ab", "abc"} { + in := "jwt eyJhbGciOiJub25lIn0." + payload + "." + sig + var out string + func() { + defer func() { + if r := recover(); r != nil { + t.Errorf("sanitizeString(%q) panicked: %v", in, r) + } + }() + out = s.sanitizeString(in) + }() + if strings.Contains(out, payload) { + t.Errorf("payload leaked: %q", out) + } + } +}