From 2dea80cfe4bfe78d4af5a6b55ef5c1450f83ae36 Mon Sep 17 00:00:00 2001 From: Rudy Celekli Date: Sun, 25 Oct 2026 11:15:40 -0400 Subject: [PATCH] fix(logs): mask Anthropic keys that contain an underscore Anthropic key bodies are base64url, so most real keys contain '_'. The anthropic_key pattern only allowed [A-Za-z0-9-], and since '_' is a word character the trailing \b could not end the match there either. A key with an early '_' was not matched at all and was logged in full. --- internal/logs/sanitizer.go | 4 ++-- internal/logs/sanitizer_anthropic_key_test.go | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 internal/logs/sanitizer_anthropic_key_test.go diff --git a/internal/logs/sanitizer.go b/internal/logs/sanitizer.go index 24dacba8d..863411395 100644 --- a/internal/logs/sanitizer.go +++ b/internal/logs/sanitizer.go @@ -66,10 +66,10 @@ func (s *SecretSanitizer) registerDefaultPatterns() { }, }) - // Anthropic API keys (sk-ant-...) + // Anthropic API keys (sk-ant-...); the body is base64url, so it carries '_'. s.patterns = append(s.patterns, &secretPattern{ name: "anthropic_key", - regex: regexp.MustCompile(`\b(sk-ant-[A-Za-z0-9\-]{30,})\b`), + regex: regexp.MustCompile(`\b(sk-ant-[A-Za-z0-9_\-]{30,})\b`), maskFunc: func(key string) string { if len(key) <= 10 { return "****" diff --git a/internal/logs/sanitizer_anthropic_key_test.go b/internal/logs/sanitizer_anthropic_key_test.go new file mode 100644 index 000000000..c5cec7c09 --- /dev/null +++ b/internal/logs/sanitizer_anthropic_key_test.go @@ -0,0 +1,23 @@ +package logs + +import ( + "strings" + "testing" +) + +func TestSanitizer_AnthropicKeyWithUnderscore(t *testing.T) { + s := newTestSanitizer() + for _, key := range []string{ + "sk-ant-api03-abcdefghij_klmnopqrstuvwxyz0123456789ABCDEFGHIJ-abcdefghijklmnopqrstuvwx_yzAA", + "sk-ant-api03-abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJ_abcdefghijklmnopqrstuvwx-yzAA", + "sk-ant-admin01-Ab_Cd-EfGhIjKlMnOpQrStUvWxYz0123456789AA", + } { + out := s.sanitizeString("using key " + key + " for upstream") + if strings.Contains(out, key[16:]) { + t.Errorf("anthropic key leaked: %q", out) + } + if !strings.Contains(out, key[:10]+"***") { + t.Errorf("anthropic key not masked by anthropic_key: %q", out) + } + } +}