Skip to content

fix: redact sensitive headers in debug logs (fixes #1196)#2977

Open
rookweb1 wants to merge 1 commit intoopenai:mainfrom
rookweb1:fix-debug-log-api-key-leak
Open

fix: redact sensitive headers in debug logs (fixes #1196)#2977
rookweb1 wants to merge 1 commit intoopenai:mainfrom
rookweb1:fix-debug-log-api-key-leak

Conversation

@rookweb1
Copy link

Description

Fixes security issue #1196 where API keys and other sensitive headers are logged in plaintext when debug logging is enabled.

Problem

When log.isEnabledFor(logging.DEBUG) is true, the make_request method logs the full options.model_dump() which includes headers with API keys (Authorization header, api-key, etc.). This is a serious security vulnerability.

Solution

Added a _redact_sensitive_headers helper method to the BaseClient class that redacts sensitive headers before logging. Modified the debug logging to use this redacted version.

Changes

  1. Added _redact_sensitive_headers method that redacts:
    • Authorization headers
    • API key headers (api-key, x-api-key, x-openai-api-key, etc.)
  2. Modified debug logging in _make_request to use redacted headers

Security Impact

Prevents accidental exposure of API keys in debug logs, which could lead to:

  • Unauthorized API access
  • Financial charges from API usage
  • Data breaches
  • Compliance violations

This is especially critical in:

  • Shared development environments
  • CI/CD pipelines with log collection
  • Production debugging scenarios

Testing

The fix maintains all existing functionality while ensuring sensitive data is never logged. All headers are still available for the actual HTTP request, only the logging is affected.

Closes #1196

Prevent API keys and other sensitive headers from being logged in plaintext when debug logging is enabled.

- Add _redact_sensitive_headers helper method
- Use redacted headers in debug logging
- Fixes security vulnerability where Authorization headers with API keys were exposed
@rookweb1 rookweb1 requested a review from a team as a code owner March 16, 2026 11:00
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cf5b851743

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

safe_options = options.model_dump()
if "headers" in safe_options:
safe_options["headers"] = self._redact_sensitive_headers(safe_options["headers"])
log.debug("Request options: %s", safe_options)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0 Badge Restore a syntactically valid debug logging block

This line terminates log.debug(...) after only two arguments, but the old indented exclude=... argument block is still present below, which makes the module fail to parse (IndentationError at import time). As a result, importing openai._base_client breaks and the SDK cannot run.

Useful? React with 👍 / 👎.

model_dump(
options,
exclude_unset=True,
safe_options = options.model_dump()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use compat model_dump for Pydantic v1 support

Calling options.model_dump() directly here drops the compatibility layer used elsewhere in the repo; under Pydantic v1, FinalRequestOptions (a pydantic.BaseModel) does not guarantee a model_dump method, so enabling DEBUG logging can raise AttributeError before the request is built. This should keep using the existing compatibility helper to avoid version-specific runtime failures.

Useful? React with 👍 / 👎.

Copy link

@alvinttang alvinttang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Bug: Broken log.debug call leaves orphaned exclude argument (syntax error at runtime)

File: src/openai/_base_client.py, around L503-510

The original code was a single log.debug(...) call that included model_dump(options, exclude_unset=True, exclude={"content", ...}). The PR replaces the first 4 lines of this multi-line expression with safe_options = options.model_dump() + log.debug(...), but leaves the remaining lines of the original expression dangling:

            safe_options = options.model_dump()
            if "headers" in safe_options:
                safe_options["headers"] = self._redact_sensitive_headers(safe_options["headers"])
            log.debug("Request options: %s", safe_options)
                    # Pydantic v1 can't dump every type we support in content, so we exclude it for now.
                    exclude={
                        "content",

The exclude={... fragment is now orphaned code — this will raise a SyntaxError (or at best be a bare dict expression with no effect, depending on surrounding context). The model_dump() call also lost the exclude_unset=True parameter and the exclude={"content", ...} filter, meaning:

  1. The debug log will now dump content fields (potentially large base64 image data) that were previously excluded
  2. Fields that were unset will now appear in the log output (noise)
  3. The code may not even parse depending on how the orphaned lines interact with the surrounding code

The fix needs to preserve the original model_dump() call's parameters and properly terminate the new log.debug() statement before removing the old lines.

Minor: _redact_sensitive_headers uses substring matching which over-matches

The any(sensitive in key_lower for sensitive in sensitive_keys) check does substring matching. A header named x-custom-api-key-version would be redacted because it contains "api-key". While this is arguably safer (erring on the side of redaction), it's worth noting that it also means the set sensitive_keys doesn't behave like a set of exact keys — it's a set of substrings. The variable name is misleading.

Consider either using exact matching (key_lower in sensitive_keys) or renaming to sensitive_patterns / sensitive_substrings to clarify intent.

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.

At debug log level API requests to OpenAI get logged with all headers, including an API key, in plaintext

2 participants