fix: use the sigv4 helper to redact session tokens from mismatch logs

The local helper masked x-amz-security-token by line prefix, which matched the
header form and missed the presigned query form entirely, leaking the token into
the exported logs on every signature mismatch. Defer to bluebottle's
RedactedCanonicalRequest, which knows the structure and masks both forms.
This commit is contained in:
Julian Sommer
2026-08-26 12:17:43 +10:00
parent 521e547c5e
commit 2eef7b2b42
2 changed files with 2 additions and 16 deletions
+1 -15
View File
@@ -141,7 +141,7 @@ func (gw *GatewayConfig) SigV4AuthMiddleware() func(http.Handler) http.Handler {
"accessKeyID", sig.Credential.AccessKeyID, "sourceIP", clientIP,
"service", sig.Credential.Service,
"action", mismatchAction(r, sig.Credential.Service),
"canonicalRequest", redactedCanonicalRequest(sig),
"canonicalRequest", sig.RedactedCanonicalRequest(),
"err", err)
// Fingerprinted by the signature as well as the key id: each guess at a
// secret produces a different one, while a client retrying an identical
@@ -213,20 +213,6 @@ func (gw *GatewayConfig) SigV4AuthMiddleware() func(http.Handler) http.Handler {
}
}
// redactedCanonicalRequest renders the server's canonical request for a mismatch log with
// the session token masked. The rest is safe: it holds signed header values and a payload
// hash, never the secret key.
func redactedCanonicalRequest(sig *sigv4.SignedRequest) string {
lines := strings.Split(sig.CanonicalRequest(), "\n")
for i, line := range lines {
if strings.HasPrefix(line, "x-amz-security-token:") {
lines[i] = "x-amz-security-token:<redacted>"
}
}
return strings.Join(lines, "\n")
}
// signingTime returns the timestamp the client signed with, read straight off the
// request. Parse rejects a skewed request before returning a SignedRequest, so the
// raw header (or the presigned query arg) is the only copy available to log.
+1 -1
View File
@@ -2214,7 +2214,7 @@ func TestRedactedCanonicalRequest_MasksSessionToken(t *testing.T) {
sig, err := sigv4.Parse(req)
require.NoError(t, err)
out := redactedCanonicalRequest(sig)
out := sig.RedactedCanonicalRequest()
assert.NotContains(t, out, token, "session token must not reach the log")
assert.Contains(t, out, "x-amz-security-token:<redacted>")
// The rest must stay intact, or the log is useless for diffing.