-
Notifications
You must be signed in to change notification settings - Fork 4.8k
fix(_logs): redact sensitive headers interpolated into log message strings #3200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,9 +34,24 @@ def setup_logging() -> None: | |
| class SensitiveHeadersFilter(logging.Filter): | ||
| @override | ||
| def filter(self, record: logging.LogRecord) -> bool: | ||
| # Case 1: headers passed as a dict in record.args (structured logging) | ||
| if is_dict(record.args) and "headers" in record.args and is_dict(record.args["headers"]): | ||
| headers = record.args["headers"] = {**record.args["headers"]} | ||
| for header in headers: | ||
| if str(header).lower() in SENSITIVE_HEADERS: | ||
| headers[header] = "<redacted>" | ||
|
|
||
| # Case 2: headers already interpolated into the log message string | ||
| # (e.g. httpx debug output: "headers={'authorization': 'Bearer sk-...'}") | ||
| import re | ||
| msg = record.getMessage() | ||
| for header in SENSITIVE_HEADERS: | ||
| # Match header: 'value' or header: "value" in the formatted message | ||
| pattern = rf"(?i)({re.escape(header)}['"]?\s*:\s*['"]?)([^'"\s,}}]+)" | ||
| redacted = re.sub(pattern, r"\1<redacted>", msg) | ||
| if redacted != msg: | ||
| record.msg = redacted | ||
| record.args = () | ||
| break | ||
|
Comment on lines
+52
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The loop stops at the first matched header ( Useful? React with 👍 / 👎. |
||
|
|
||
| return True | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new regex only replaces characters up to the first whitespace (
[^'"\s,}}]+), so anAuthorizationvalue likeBearer sk-...becomes<redacted> sk-...and still leaks the token. This is the common HTTP auth format, so debug logs can continue exposing credentials even after this fix.Useful? React with 👍 / 👎.