From ce3670892d387446192bb1182d5b37dc82a4b80e Mon Sep 17 00:00:00 2001 From: Oleksii Maksymov Date: Mon, 20 Jul 2026 12:16:14 +0300 Subject: [PATCH] Redact credentials from server.log run_curl() logged the full curl command line to server.log before executing it, including the raw HTTP Basic Auth token from --user : for the http_basic auth method, and the session cookie from -b for the gitcookies auth method. Both end up sitting in plaintext in a log file on disk. Mask the credential-bearing arguments before writing the log line. The actual curl invocation is unchanged; only what gets logged is redacted. --- gerrit_mcp_server/main.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/gerrit_mcp_server/main.py b/gerrit_mcp_server/main.py index 9ad3571..890e23b 100644 --- a/gerrit_mcp_server/main.py +++ b/gerrit_mcp_server/main.py @@ -182,12 +182,26 @@ def _normalize_gerrit_url(url: str, gerrit_hosts: List[Dict[str, Any]]) -> str: return normalized_url +def _redact_command_for_logging(command: List[str]) -> List[str]: + """Returns a copy of a curl command with credentials masked for logging.""" + redacted = list(command) + for i, arg in enumerate(redacted): + if arg == "--user" and i + 1 < len(redacted): + user_part = redacted[i + 1].split(":", 1)[0] + redacted[i + 1] = f"{user_part}:***REDACTED***" + elif arg == "-b" and i + 1 < len(redacted): + redacted[i + 1] = "***REDACTED***" + return redacted + + async def run_curl(args: List[str], gerrit_base_url: str) -> str: """Executes a curl command and returns the output.""" config = load_gerrit_config() command = get_curl_command_for_gerrit_url(gerrit_base_url, config) + args with open(LOG_FILE_PATH, "a") as log_file: - log_file.write(f"[gerrit-mcp-server] Executing: {" ".join(command)}\n") + log_file.write( + f"[gerrit-mcp-server] Executing: {' '.join(_redact_command_for_logging(command))}\n" + ) process = await asyncio.create_subprocess_exec( *command,