From fd37a67ef888c6ca7b49cc43e473e3b54e5781fb Mon Sep 17 00:00:00 2001 From: Rogee Date: Sat, 10 Oct 2026 00:26:38 +0800 Subject: [PATCH] fix: redact private keys and signed websocket endpoints --- internal/logging/logging_test.go | 13 +++++++++++++ internal/logging/redact.go | 6 +++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/internal/logging/logging_test.go b/internal/logging/logging_test.go index c972350..d4d2a91 100644 --- a/internal/logging/logging_test.go +++ b/internal/logging/logging_test.go @@ -105,6 +105,19 @@ func TestUnstructuredAndEmbeddedJSONCannotLeakCredentials(t *testing.T) { } } +func TestPrivateKeyAndSignedWebSocketURLNeverLeakInEitherMode(t *testing.T) { + for _, debug := range []bool{false, true} { + out := installTestLogger(t, debug) + slog.Info("workflow", "private_key", "private-key-value", "client_key_pem", "private-pem-value", "endpoint", "wss://user:private-password@host/ws?Signature=private-signature") + Body(context.Background(), "HTTP data", []byte(`{"privateKey":"private-key-value","ws_endpoint":"wss://host/ws?Signature=private-signature"}`)) + for _, secret := range []string{"private-key-value", "private-pem-value", "private-password", "private-signature"} { + if strings.Contains(out.String(), secret) { + t.Fatalf("leaked %s: %s", secret, out.String()) + } + } + } +} + func TestSensitiveWorkflowFieldsAndURLsNeverLeak(t *testing.T) { out := installTestLogger(t, true) slog.Info("workflow", "Authorization", "Bearer do-not-print", "apiKey", "do-not-print", "prompt", "do-not-print", "url", "https://user:pass@host/path?signature=do-not-print") diff --git a/internal/logging/redact.go b/internal/logging/redact.go index 25bb02f..0682a49 100644 --- a/internal/logging/redact.go +++ b/internal/logging/redact.go @@ -23,7 +23,7 @@ func sensitive(key string) bool { return -1 }, key) switch normalized { - case "content", "headers", "history", "sentence", "sentences", "words", "openingremark", "openingremarks", "greeting", "sessionnonce", "credential", "credentials", "key", "authorization", "proxyauthorization", "apikey", "accesskeyid", "accesskeysecret", "appkey", "appsecret", "secret", "secretkey", "password", "passwd", "token", "accesstoken", "refreshtoken", "uploadtoken", "providertoken", "sessioncredential", "clientnonce", "servernonce", "cookie", "setcookie", "prompt", "systemprompt", "instructions", "messages", "messagecontent", "transcript", "transcription", "finaltranscript", "text", "utterance", "audio", "audiodata", "recordingdata", "raw", "closingremark", "signature", "targeturl": + case "privatekey", "privatekeypem", "clientkey", "clientkeypem", "serverkey", "serverkeypem", "content", "headers", "history", "sentence", "sentences", "words", "openingremark", "openingremarks", "greeting", "sessionnonce", "credential", "credentials", "key", "authorization", "proxyauthorization", "apikey", "accesskeyid", "accesskeysecret", "appkey", "appsecret", "secret", "secretkey", "password", "passwd", "token", "accesstoken", "refreshtoken", "uploadtoken", "providertoken", "sessioncredential", "clientnonce", "servernonce", "cookie", "setcookie", "prompt", "systemprompt", "instructions", "messages", "messagecontent", "transcript", "transcription", "finaltranscript", "text", "utterance", "audio", "audiodata", "recordingdata", "raw", "closingremark", "signature", "targeturl": return true } return strings.HasSuffix(normalized, "password") || strings.HasSuffix(normalized, "secret") || strings.HasSuffix(normalized, "apikey") || strings.HasSuffix(normalized, "token") || strings.HasSuffix(normalized, "text") @@ -139,9 +139,9 @@ func RedactJSON(body []byte) (string, error) { } var ( - urlInText = regexp.MustCompile(`https?://[^\s<>"']+`) + urlInText = regexp.MustCompile(`(?:https?|wss?)://[^\s<>"']+`) bearerInText = regexp.MustCompile(`(?i)\bBearer\s+[^\s,;"']+`) - secretInText = regexp.MustCompile(`(?i)\b(api[_-]?key|access[_-]?key[_-]?(secret|id)|password|token|secret|signature|prompt|system[_-]?prompt|content|transcript|text)["']?\s*[=:]\s*(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s,;"']+)`) + secretInText = regexp.MustCompile(`(?i)\b(api[_-]?key|private[_-]?key(?:[_-]?pem)?|client[_-]?key(?:[_-]?pem)?|access[_-]?key[_-]?(secret|id)|password|token|secret|signature|prompt|system[_-]?prompt|content|transcript|text)["']?\s*[=:]\s*(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s,;"']+)`) ) // Error messages can contain a provider's JSON response after a text prefix.