Skip to content

Commit 0cfb7eb

Browse files
authored
fix(logs): don't panic masking a JWT with a short signature (#1761)
## Bug The log sanitizer's `jwt` regex accepts any non-empty third segment (`[A-Za-z0-9\-_]+`), but its mask function always takes the last four characters with `parts[2][len(parts[2])-4:]`. A JWT-shaped string with a 1–3 character signature panics with `slice bounds out of range` inside `SecretSanitizer.Write`, which zap does not recover. The process logging the line crashes. ## Trigger Any log message or field containing, for example: ``` eyJhbGciOiJub25lIn0.eyJzdWIiOiIxIn0.x ``` This can come from upstream tool output, an error body echoed into a log, or a test or unsigned token. The result is `panic: runtime error: slice bounds out of range [-3:]`. ## Fix When the signature is shorter than four characters, mask it fully (`<header>.***.***`) instead of slicing. This touches the same `jwt` block that #1760 moves. Whichever lands second needs a trivial rebase. ## Test `TestSanitizer_JWTShortSignatureDoesNotPanic` runs signatures of length 1, 2 and 3 through `sanitizeString`, recovers any panic, and checks that the payload is masked. ## Commands run - `CGO_ENABLED=0 go test -count=1 ./internal/logs`: ok - Without the fix, the new test fails on all three inputs with `panicked: runtime error: slice bounds out of range [-3:]`, `[-2:]` and `[-1:]`. - `gofmt -l` on the edited files: no output
1 parent 4eb1b78 commit 0cfb7eb

2 files changed

Lines changed: 31 additions & 0 deletions

File tree

‎internal/logs/sanitizer.go‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ func (s *SecretSanitizer) registerDefaultPatterns() {
114114
if len(parts) != 3 {
115115
return "****"
116116
}
117+
if len(parts[2]) < 4 {
118+
return parts[0] + ".***.***"
119+
}
117120
// Show first part (header) but mask payload and signature
118121
return parts[0] + ".***." + parts[2][len(parts[2])-4:]
119122
},
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package logs
2+
3+
import (
4+
"strings"
5+
"testing"
6+
)
7+
8+
// The jwt regex accepts a 1-3 character signature segment; masking it must
9+
// not slice out of range (a panic inside the zap core takes the caller down).
10+
func TestSanitizer_JWTShortSignatureDoesNotPanic(t *testing.T) {
11+
s := newTestSanitizer()
12+
const payload = "eyJzdWIiOiIxIn0"
13+
for _, sig := range []string{"x", "ab", "abc"} {
14+
in := "jwt eyJhbGciOiJub25lIn0." + payload + "." + sig
15+
var out string
16+
func() {
17+
defer func() {
18+
if r := recover(); r != nil {
19+
t.Errorf("sanitizeString(%q) panicked: %v", in, r)
20+
}
21+
}()
22+
out = s.sanitizeString(in)
23+
}()
24+
if strings.Contains(out, payload) {
25+
t.Errorf("payload leaked: %q", out)
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)