fix(log): redact sensitive auth headers from request logs

The trace-level request log dumps all headers as a JSON blob, but the
redaction hook only had query-param patterns, so Authorization, X-Emby-Token,
X-MediaBrowser-Token and X-Nd-Authorization leaked their tokens in plaintext.
Add one pattern that blanks those header value arrays at the log sink.
This commit is contained in:
Deluan 2026-08-23 15:24:44 -04:00
parent 3e55886195
commit 82b9a44a1f
2 changed files with 21 additions and 1 deletions

View File

@ -50,6 +50,10 @@ var redacted = &Hook{
// at a JWT's first '.' and leak its payload and signature. Case-insensitive with an
// optional underscore: the API accepts api_key, apikey and ApiKey alike.
"(?i)([^\\w]api_?key=)[^&\\s]+",
// Sensitive request headers, logged as a JSON blob at trace level and never matched by the
// query-param patterns above. Blank the whole value array; values may hold escaped quotes.
`(?i)("(?:Authorization|X-Emby-Token|X-MediaBrowser-Token|X-Nd-Authorization)":\[")[^\]]*("\])`,
},
}

View File

@ -2,7 +2,9 @@ package log
import (
"context"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"testing"
"time"
@ -92,7 +94,7 @@ var _ = Describe("Logger", func() {
SetLogSourceLine(true)
Error("A crash happened")
// NOTE: This assertion breaks if the line number above changes
Expect(hook.LastEntry().Data[" source"]).To(ContainSubstring("/log/log_test.go:93"))
Expect(hook.LastEntry().Data[" source"]).To(ContainSubstring("/log/log_test.go:95"))
Expect(hook.LastEntry().Message).To(Equal("A crash happened"))
})
@ -275,5 +277,19 @@ var _ = Describe("Logger", func() {
Entry("ApiKey", "ApiKey"),
Entry("APIKEY", "APIKEY"),
)
It("redacts sensitive request headers in a logged header blob", func() {
h := http.Header{
"Authorization": {`MediaBrowser Client="Finamp", Token="jwt-secret"`},
"X-Emby-Token": {"emby-secret"},
"X-Mediabrowser-Token": {"mb-secret"},
"X-Nd-Authorization": {"Bearer nd-secret"},
"User-Agent": {"Finamp/1.0"},
}
blob, _ := json.Marshal(h)
got := Redact(string(blob))
Expect(got).ToNot(ContainSubstring("secret"))
Expect(got).To(ContainSubstring(`"User-Agent":["Finamp/1.0"]`))
})
})
})