Skip to content

fix: redact Authorization header from websockets DEBUG logs#731

Merged
GregHolmes merged 1 commit into
mainfrom
gh/redact-websocket-auth-logs
Jun 18, 2026
Merged

fix: redact Authorization header from websockets DEBUG logs#731
GregHolmes merged 1 commit into
mainfrom
gh/redact-websocket-auth-logs

Conversation

@GregHolmes

Copy link
Copy Markdown
Contributor

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 websockets library, which logs the full opening handshake at DEBUG, one record per header, via logger.debug("> %s: %s", name, value). That includes Authorization: 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.Filter on the websockets.client / websockets.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 the app's log level.

  • The auth scheme is preserved for debuggability; only the secret is replaced: Authorization: Token [REDACTED].
  • Nothing is suppressed and no other log output changes.
  • On by default (installed from both client constructors, idempotent). Opt out with 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 on websockets.client with no per-connection child loggers, so a filter there sees every header record before propagation.

Files

  • src/deepgram/_secure_logging.py — hand-written RedactCredentialsFilter + install/uninstall helpers (frozen in .fernignore)
  • src/deepgram/client.py — install from DeepgramClient / AsyncDeepgramClient constructors + opt-out kwarg
  • tests/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 also websockets DEBUG 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 the websockets logger level, which would also drop the handshake debug some users rely on. Recommended app-side mitigation (documented, not forced):

import logging
logging.getLogger("websockets").setLevel(logging.INFO)  # quiet per-frame logs, keep your app at DEBUG

Validation

  • ruff check — clean
  • mypy — clean
  • pytest — 237 passed, 1 skipped (12 new)

🤖 Generated with Claude Code

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.
@GregHolmes GregHolmes merged commit 029d877 into main Jun 18, 2026
10 checks passed
@GregHolmes GregHolmes deleted the gh/redact-websocket-auth-logs branch June 18, 2026 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants