From d6909bf4d73aa2c917bc69134645458c7b1fcbe0 Mon Sep 17 00:00:00 2001 From: pax Date: Sat, 11 Apr 2026 16:12:28 -0500 Subject: [PATCH] =?UTF-8?q?security:=20fix=20#3=20=E2=80=94=20redact=20URL?= =?UTF-8?q?=20in=20BooruClient.=5Flog=5Frequest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The httpx request event hook converts request.url to a str so log_connection can parse it — at that point the credential query params (login, api_key, etc.) are in scope and could be captured by any traceback, debug hook, or monitoring agent observing the hook call. Pipe through redact_url() first so the rendered string never carries the secrets, even transiently. Audit-Ref: SECURITY_AUDIT.md finding #3 Severity: Medium --- booru_viewer/core/api/base.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/booru_viewer/core/api/base.py b/booru_viewer/core/api/base.py index d4c2347..f030fb4 100644 --- a/booru_viewer/core/api/base.py +++ b/booru_viewer/core/api/base.py @@ -12,7 +12,7 @@ import httpx from ..config import USER_AGENT, DEFAULT_PAGE_SIZE from ..cache import log_connection -from ._safety import validate_public_request +from ._safety import redact_url, validate_public_request log = logging.getLogger("booru") @@ -133,7 +133,11 @@ class BooruClient(ABC): @staticmethod async def _log_request(request: httpx.Request) -> None: - log_connection(str(request.url)) + # Redact api_key / login / user_id / password_hash from the + # URL before it ever crosses the function boundary — the + # rendered URL would otherwise land in tracebacks, debug logs, + # or in-app connection-log views as plaintext. + log_connection(redact_url(str(request.url))) _RETRYABLE_STATUS = frozenset({429, 503})