From 2de4796e2858d85e73b520658663fa239740d38c Mon Sep 17 00:00:00 2001 From: Rudy Celekli Date: Sun, 25 Oct 2026 11:24:25 -0400 Subject: [PATCH] fix(oauth): redact the whole of a base64 Bearer token tokenPattern stopped at the first character outside [A-Za-z0-9-_.], so a standard-base64 token was redacted only up to its first '+' or '/' and the rest stayed in the text. Use RFC 6750's b64token class (adds ~ + / and trailing =), as the log sanitizer's bearer pattern already does. --- internal/oauth/logging.go | 6 ++++-- internal/oauth/logging_test.go | 7 +++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/internal/oauth/logging.go b/internal/oauth/logging.go index 6a5cde542..1f0d676ac 100644 --- a/internal/oauth/logging.go +++ b/internal/oauth/logging.go @@ -137,8 +137,10 @@ var sensitiveParams = []string{ "credential", } -// tokenPattern matches Bearer tokens and other sensitive token patterns. -var tokenPattern = regexp.MustCompile(`(?i)(bearer\s+)[a-zA-Z0-9\-_\.]+`) +// tokenPattern matches Bearer tokens and other sensitive token patterns. The +// value class is RFC 6750's b64token, so a standard-base64 token is not cut at +// its first '+' or '/'. +var tokenPattern = regexp.MustCompile(`(?i)(bearer\s+)[a-zA-Z0-9\-_\.~+/]+=*`) // secretPattern matches common secret patterns. var secretPattern = regexp.MustCompile(`(?i)(secret|password|token|key)["']?\s*[:=]\s*["']?[a-zA-Z0-9\-_\.]+`) diff --git a/internal/oauth/logging_test.go b/internal/oauth/logging_test.go index c86a58c17..65fd51806 100644 --- a/internal/oauth/logging_test.go +++ b/internal/oauth/logging_test.go @@ -17,6 +17,13 @@ func TestRedactSensitiveData(t *testing.T) { assert.NotContains(t, result, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9") }) + t.Run("redacts the whole of a base64 bearer token", func(t *testing.T) { + // RFC 6750 b64token: '+', '/', '~' and trailing '=' are all legal. + input := "upstream rejected Bearer dGhpcy1pcy1h+c2VjcmV0/dG9rZW4~cGFydA== (401)" + result := RedactSensitiveData(input) + assert.Equal(t, "upstream rejected Bearer ***REDACTED*** (401)", result) + }) + t.Run("redacts secrets in key=value format", func(t *testing.T) { input := "client_secret=my-super-secret-value" result := RedactSensitiveData(input)