Skip to content

Mask credentials in transport-level request failures - #341

Open
Flerpharos wants to merge 1 commit into
mainfrom
fix/338-transport-exception-credential-leak
Open

Mask credentials in transport-level request failures#341
Flerpharos wants to merge 1 commit into
mainfrom
fix/338-transport-exception-credential-leak

Conversation

@Flerpharos

Copy link
Copy Markdown
Collaborator

What

Fixes #338 (HIGH, security). A connection/DNS/TLS/proxy failure raised the raw requests exception, which embeds the full signed URL — including password=<auth_code>, login_or_email, akid, expires, sig. The existing credential masking only ran for HTTP-status errors in _handle_request_status; transport exceptions produce no response and bypassed it, leaking a live one-hour auth code and a replayable signed URL into logs/tracebacks.

Fix

  • Extract the query-param masking into a module-level _mask_sensitive_url() (also now used by the status-error path — no behavior change there).
  • Route all four request methods (stream_api_get/post, raw_api_get/post) through a new _send() helper that catches requests.RequestException and re-raises it as an ApiError with the URL masked, using from None so the unmasked URL doesn't survive on __cause__.

The detail is preserved by masking the known request URL within the exception text, so error messages stay useful without the credentials.

Verification

New test test_transport_exception_masks_credentials (forces a transport failure carrying the real signed URL; asserts the auth code, akid, and email are absent and password=*** is present). Existing test_client_handle_request_status_sanitizes_url still passes. Full suite 431 passed, 1 skipped; ruff/pyright clean.

Fixes #338.

🤖 Generated with Claude Code

A connection/DNS/TLS/proxy failure raised the raw requests exception, which
embeds the full signed URL -- including password=<auth_code>, login_or_email,
akid, expires, and sig. The existing masking only ran for HTTP-status errors
in _handle_request_status; transport exceptions produce no response and
bypassed it, leaking a live auth code and replayable signed URL into logs and
tracebacks.

Extract the query-param masking into `_mask_sensitive_url()` (reused by the
status-error path), and route all four request methods through a new `_send()`
helper that catches `requests.RequestException` and re-raises it as an ApiError
with the URL masked, suppressing the original (`from None`) so the unmasked URL
does not survive on `__cause__`.

Fixes #338.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

Transport-level request failures leak credentials and signed URLs

1 participant