Fix/redact sensitive auth logs - #333
Conversation
|
Welcome to the Microcks community! 💖 Thanks and congrats 🎉 for opening your first pull request here! Be sure to follow the pull request template or please update it accordingly. Hope you have a great time there! |
d9a0239 to
572d7d0
Compare
|
Hii @lbroudoux, @yada , @Harsh4902 could you please take a look at this PR when you get a chance? Would appreciate your review |
Introduce a new pkg/utils/sanitize.go package with utilities to redact sensitive values before they are written to logs or stdout: - MaskSecret: replaces any non-empty secret with '[REDACTED]' - SanitizeHeaders: returns a copy of http.Header with sensitive header values replaced - SanitizeJSON: recursively redacts sensitive keys in JSON payloads - SanitizeString: handles raw HTTP dump strings (CRLF/LF), sanitizing headers, Authorization scheme tokens, and URL-encoded form fields (access_token=, client_secret=, password=, etc.) Sensitive key matching is case-insensitive and covers authorization, proxy-authorization, access_token, refresh_token, id_token, client_secret, password, token, api_key, cookie, set-cookie, x-api-key. Also adds sanitize_test.go with 7 unit tests covering all helpers. Closes microcks#265 Signed-off-by: Priyanshubhartistm <bhartipriyanshustm@gmail.com>
DumpRequestIfRequired and DumpResponseIfRequired previously printed raw httputil dump output directly to stdout, which included Authorization headers (Basic and Bearer), token response bodies, and form-encoded secrets when --verbose was active. Pass the dump through utils.SanitizeString before printing so that all sensitive headers and body values are replaced with '[REDACTED]'. This single fix covers all callers across the codebase: - pkg/connectors/keycloak_client.go (Keycloak auth requests/responses) - pkg/connectors/microcks_client.go (Microcks API requests/responses) Fixes microcks#265 Signed-off-by: Priyanshubhartistm <bhartipriyanshustm@gmail.com>
The oauth2login function logged the raw access token and refresh token directly via log.Printf, making them visible in any terminal or CI/CD log where --verbose is active. - Replace token log calls with utils.MaskSecret so the values are always printed as '[REDACTED]' regardless of --verbose state - Sanitize the OAuth2 callback URL logged on each redirect using utils.SanitizeString to redact any authorization codes or state params that may appear in query strings Fixes microcks#265 Signed-off-by: Priyanshubhartistm <bhartipriyanshustm@gmail.com>
572d7d0 to
453b88e
Compare
| log.Printf("Token: %s\n", utils.MaskSecret(tokenString)) | ||
| log.Printf("Refresh Token: %s\n", utils.MaskSecret(refreshToken)) |
There was a problem hiding this comment.
These two log.Printf lines are added unconditionally (outside any --verbose guard). The original code didn't log tokens at all after the server shutdown. Now every SSO login prints [REDACTED] tokens to the terminal. Not a security leak since you're masking them, but it's adding new output that wasn't there before. Is that intentional? Might confuse users or break scripts that parse stdout.
| if sanitized, ok := sanitizeHTTPDump(input); ok { | ||
| return sanitized | ||
| } | ||
|
|
There was a problem hiding this comment.
SanitizeJSON uses json.Marshal which produces compact JSON. If the original dump was indented/prettified for debugging, the sanitized output comes back minified. Could be disorienting when comparing before/after. Consider using json.MarshalIndent to preserve formatting.
There was a problem hiding this comment.
No tests for empty/nil inputs in SanitizeString or SanitizeHeaders. SanitizeString("") should return "" but it's not verified.
| func TestSanitizeStringHeadersAndForm(t *testing.T) { | ||
| input := "Authorization: Bearer abc\nX-Api-Key: key\nContent-Type: text/plain\n\nclient_secret=secret&grant_type=password" | ||
| sanitized := SanitizeString(input) | ||
|
|
||
| if !containsLine(sanitized, "Authorization: "+redactedValue) { | ||
| t.Fatalf("expected authorization header redacted") | ||
| } | ||
| if !containsLine(sanitized, "X-Api-Key: "+redactedValue) { | ||
| t.Fatalf("expected api key header redacted") | ||
| } | ||
| if !containsLine(sanitized, "Content-Type: text/plain") { | ||
| t.Fatalf("expected content-type preserved") | ||
| } | ||
| if !containsLine(sanitized, "client_secret="+redactedValue+"&grant_type=password") { | ||
| t.Fatalf("expected form secret redacted") | ||
| } | ||
| } |
There was a problem hiding this comment.
containsLine uses plain strings.Contains, not an actual line-boundary check. The name is misleading, a match inside a longer string would pass. Fine for these tests but worth renaming to containsSubstr or similar for clarity.
|
@Vaishnav88sk ,sure, I will resolve the merge conflicts as soon as possible |
|
Fixed on master — verbose dumps now pass through redaction that masks the Authorization header and token query params (access_token/refresh_token/id_token/code). One residual nit: client_secret= isn't in the param regex yet, worth a tiny follow-up PR, but the leak reported here is closed. I believe this can be closed (happy to review ones you file the small follow-up from updated upstream master). |
Description
pkg/utilspackage with sanitization helpers (SanitizeString,SanitizeJSON,SanitizeHeaders,MaskSecret) that redact sensitive values before they are written to logs or stdout.DumpRequestIfRequiredandDumpResponseIfRequiredinpkg/config/config.goto pass all raw HTTP dump output throughSanitizeStringbefore printing, ensuringAuthorization: Basic/Bearerheaders,access_token/refresh_tokenresponse bodies, and URL-encoded form secrets (e.g.client_secret=) are always replaced with[REDACTED]— this single change covers all callers acrosskeycloak_client.goandmicrocks_client.go.cmd/login.goto mask the SSO access token and refresh token withMaskSecretbefore logging, and to sanitize the OAuth2 callback URL withSanitizeStringto prevent authorization codes from leaking in log output.pkg/utils/sanitize_test.gocoveringMaskSecret,SanitizeHeaders, nested JSON redaction, case-insensitive key matching, malformed JSON passthrough, HTTP dump with form body, and Basic auth header redaction.Before (with
--verbose):After (with
--verbose):Test results
Related issue(s)
Fixes #265