fix: redact Authorization header from websockets DEBUG logs#731
Merged
Conversation
The third-party websockets library logs the full opening handshake at DEBUG level, including the Authorization header (API key / access token) in clear text, plus one record per audio frame. Applications that enable DEBUG logging during development would write the credential into their logs, from where it is easily committed or shipped to a log aggregator. Install a logging.Filter on the websockets client/server loggers that masks the value of Authorization / Proxy-Authorization headers before the record reaches any handler — so the credential is never emitted regardless of log level. The auth scheme (Token/bearer) is preserved for debuggability; only the secret is replaced with [REDACTED]. On by default; opt out via DeepgramClient(redact_credentials_in_logs=False). - src/deepgram/_secure_logging.py: hand-written filter + install/uninstall - client.py: install from both client constructors (idempotent) - tests/custom/test_secure_logging.py: regression coverage Reported by an external user against v4.8.1; reproduced and fixed on current. Validation: ruff clean, mypy clean, pytest 237 passed / 1 skipped.
dg-coreylweathers
approved these changes
Jun 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes an externally-reported security issue: the API key / access token is written to application logs in clear text when DEBUG logging is enabled.
The leak is not in Deepgram's code — it's the third-party
websocketslibrary, which logs the full opening handshake at DEBUG, one record per header, vialogger.debug("> %s: %s", name, value). That includesAuthorization: Token <key>. Any app that turns on DEBUG (common in dev/troubleshooting) then writes the credential to its logs, from where it's easily committed or shipped to a log aggregator.Fix
Install a
logging.Filteron thewebsockets.client/websockets.serverloggers that masks the value ofAuthorization/Proxy-Authorizationheaders before the record reaches any handler — so the credential is never emitted, regardless of the app's log level.Authorization: Token [REDACTED].DeepgramClient(redact_credentials_in_logs=False)to manage redaction yourself.Confirmed the filter reliably catches the record:
websockets >= 12(our floor) emits handshake headers directly onwebsockets.clientwith no per-connection child loggers, so a filter there sees every header record before propagation.Files
src/deepgram/_secure_logging.py— hand-writtenRedactCredentialsFilter+install/uninstallhelpers (frozen in.fernignore)src/deepgram/client.py— install fromDeepgramClient/AsyncDeepgramClientconstructors + opt-out kwargtests/custom/test_secure_logging.py— regression coverage (token masked, scheme preserved, non-sensitive headers untouched, idempotent install, opt-out)On the per-frame logging
The reporter also noted
BINARY ... [N bytes]spam per audio frame. That's alsowebsocketsDEBUG output, but it contains no secret (payloads are shown only as byte counts), so it's a verbosity concern, not a disclosure. Silencing it by default would require raising thewebsocketslogger level, which would also drop the handshake debug some users rely on. Recommended app-side mitigation (documented, not forced):Validation
ruff check— cleanmypy— cleanpytest— 237 passed, 1 skipped (12 new)🤖 Generated with Claude Code