Skip to content

Sensitive header reference

The two header-related symbols answer a narrow question: which header names carry secrets? Neither one redacts anything — masking the value is the caller's job, and Redact HTTP headers shows how to wire that up.

The curated list: SensitiveHeaderKeys

redact.SensitiveHeaderKeys contains exactly ten entries, in this order:

# Header
1 Authorization
2 Proxy-Authorization
3 Cookie
4 Set-Cookie
5 X-API-Key
6 X-API-Token
7 X-Auth-Token
8 X-Access-Token
9 X-CSRF-Token
10 X-Session-Token

Comparison against this list is case-insensitive: the entries are lowercased into a lookup map at package init, and the name you pass is lowercased too.

The list is exported for composition, not for editing — appending to it does not change what IsSensitiveHeaderKey returns. See Treat SensitiveHeaderKeys as read-only.

Four of the entries are guarded by TestSensitiveHeaderKeys_ContainsCoreSet against accidental deletion — Authorization, Cookie, Set-Cookie and X-API-Key — because external consumers rely on them.

The wider fuzzy match

IsSensitiveHeaderKey returns true for anything on the curated list and for any name matching this pattern:

regexp.MustCompile(`(?i)\b(auth|token|key|secret|bearer|password|credential)\b|authorization`)

So a name qualifies if it contains any of these as a whole word:

auth, token, key, secret, bearer, password, credential

or contains authorization anywhere, whole word or not.

Word boundaries follow the ASCII rule where letters, digits and _ are word characters and everything else — including - — is a separator. Header names are hyphen-separated, so each component of X-Auth-Token is a word in its own right.

The two mechanisms answer different questions. Use the curated list when you are deciding what your own code should mask by policy; use IsSensitiveHeaderKey when you are deciding whether an operator-supplied header name might be hiding a secret, where erring toward redaction is the safe direction.

Which names match, and which do not

Header name IsSensitiveHeaderKey Why
Authorization true Curated list
authorization true Comparison is case-insensitive
" Authorization " true Surrounding whitespace is trimmed first
Proxy-Authorization true Contains authorization
Cookie / Set-Cookie true Curated list
X-API-Key true Curated list, and whole word key
X-Custom-Auth true Whole word auth
X-User-Password true Whole word password
X-Amz-Security-Token true Whole word token
X-Bearer-Only true Whole word bearer
X-Key-Id true Whole word key
Public-Key-Pins true Whole word key — a false positive
Content-Type false No credential word
Accept / User-Agent / Referer false No credential word
X-Request-ID false No credential word
Location false No credential word, though a redirect target can carry a token
X-Apikey false apikey is a single word; the pattern wants key alone
Authentication false Not authorization, and auth is not a whole word here
Www-Authenticate false Same reason
Cookie2 false Not an exact list entry, and cookie is not in the fuzzy word list
"" false Empty short-circuits before matching

The pattern is word-based, so glued spellings escape it: X-API-Key matches and X-Apikey does not. If your service accepts either spelling, test for the glued form yourself as well.

http.Header canonicalises keys when you use Set/Get, but ranging over the map gives you whatever form was stored. IsSensitiveHeaderKey lowercases and trims for you, so you do not need to normalise the name before calling it.

Header values are not redacted for you

redact.String has no rule for a generic Name: value header line. Only authorization: followed by Bearer, Basic, Digest or ApiKey is recognised, and that is what makes the two header symbols necessary:

Authorization: Bearer abc123def456   →  Authorization: Bearer ***
X-API-Key: abc123def456ghijklmno     →  unchanged
Cookie: session=deadbeef             →  unchanged

Pass header names through IsSensitiveHeaderKey and mask the values yourself. Running the values you keep through String afterwards is a useful second pass — it catches a token embedded in a Location redirect — but it is not a substitute for the first.