From a055c8fa744cfc0024b00ebad5e02b8b51829fbf Mon Sep 17 00:00:00 2001 From: Stanislav Novosad Date: Fri, 10 Oct 2025 19:56:47 -0600 Subject: [PATCH] Mask logged body for sensitive endpoints (#3689) Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> --- skyvern/forge/request_logging.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/skyvern/forge/request_logging.py b/skyvern/forge/request_logging.py index 0295148d..093ac356 100644 --- a/skyvern/forge/request_logging.py +++ b/skyvern/forge/request_logging.py @@ -15,6 +15,11 @@ if typing.TYPE_CHECKING: # pragma: no cover - import only for type hints LOG = structlog.get_logger() _SENSITIVE_HEADERS = {"authorization", "cookie", "x-api-key"} +_SENSITIVE_ENDPOINTS = { + "POST /api/v1/credentials", + "POST /v1/credentials/onepassword/create", + "POST /v1/credentials/azure_credential/create", +} _MAX_BODY_LENGTH = 1000 _BINARY_PLACEHOLDER = "" @@ -28,7 +33,9 @@ def _sanitize_headers(headers: typing.Mapping[str, str]) -> dict[str, str]: return sanitized -def _sanitize_body(body: bytes, content_type: str | None) -> str: +def _sanitize_body(request: Request, body: bytes, content_type: str | None) -> str: + if f"{request.method.upper()} {request.url.path.rstrip('/')}" in _SENSITIVE_ENDPOINTS: + return "****" if not body: return "" if content_type and not (content_type.startswith("text/") or content_type.startswith("application/json")): @@ -54,7 +61,7 @@ async def log_raw_request_middleware(request: Request, call_next: Callable[[Requ pass sanitized_headers = _sanitize_headers(dict(request.headers)) - body_text = _sanitize_body(body_bytes, request.headers.get("content-type")) + body_text = _sanitize_body(request, body_bytes, request.headers.get("content-type")) LOG.info( "api.raw_request",