Skip to content

Commit 210aaa2

Browse files
committed
Add MCP tool name logging, sync PII sanitization across loggers
- Log MCP tool calls in mcp_server.py (method, path, status, client IP) - Add _safe_path() with PII redaction matching main.py pattern - Sync _LOG_SANITIZE regex: +7 endpoints (archive, username, cve, cves, exploit, hash, epss) - Harden control char stripping: \n\r → full C0 range + DEL ([\x00-\x1f\x7f])
1 parent 279b349 commit 210aaa2

2 files changed

Lines changed: 21 additions & 2 deletions

File tree

app/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,13 @@ async def _periodic_maintenance():
156156
_MAX_TRACKED_PATHS = 200
157157

158158
_LOG_SANITIZE = re.compile(
159-
r"/v1/(phone|email/mx|email/disposable|ip|domain|dns|whois|subdomains|certs|ssl|threat|tech|monitor|ioc|phishing|scan/headers|asn|password)/[^/?]+"
159+
r"/v1/(phone|email/mx|email/disposable|ip|domain|dns|whois|subdomains|certs|ssl|threat|tech|monitor|ioc|phishing|scan/headers|asn|password|archive|username|cve|cves|exploit|hash|epss)/[^/?]+"
160160
)
161161

162162

163163
def _sanitize_path(path: str) -> str:
164164
"""Redact PII (domains, IPs, emails, phones) from request paths for safe logging."""
165-
safe = path.replace("\n", "").replace("\r", "")
165+
safe = re.sub(r"[\x00-\x1f\x7f]", "", path)
166166
return _LOG_SANITIZE.sub(r"/v1/\1/***", safe)
167167

168168

mcp_server.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import contextvars
2121
import logging
2222
import os
23+
import re
2324
import sys
2425

2526
import httpx
@@ -49,6 +50,16 @@
4950
API_KEY = os.environ.get("CONTRASTAPI_KEY", "")
5051
TIMEOUT = 30.0
5152

53+
_LOG_SANITIZE = re.compile(
54+
r"/v1/(phone|email/mx|email/disposable|ip|domain|dns|whois|subdomains|certs|ssl|threat|tech|monitor|ioc|phishing|scan/headers|asn|password|archive|username|cve|cves|exploit|hash|epss)/[^/?]+"
55+
)
56+
57+
58+
def _safe_path(path: str) -> str:
59+
"""Redact PII from API paths for safe logging."""
60+
safe = re.sub(r"[\x00-\x1f\x7f]", "", path)
61+
return _LOG_SANITIZE.sub(r"/v1/\1/***", safe)
62+
5263

5364
def _headers() -> dict:
5465
h = {"Accept": "application/json"}
@@ -62,6 +73,7 @@ def _headers() -> dict:
6273

6374

6475
async def _get(path: str, params: dict | None = None) -> dict | str:
76+
client_ip = _client_ip_var.get() or "unknown"
6577
async with httpx.AsyncClient() as client:
6678
try:
6779
resp = await client.get(
@@ -71,14 +83,18 @@ async def _get(path: str, params: dict | None = None) -> dict | str:
7183
headers=_headers(),
7284
)
7385
resp.raise_for_status()
86+
logger.info("mcp_tool GET %s %d %s", _safe_path(path), resp.status_code, client_ip)
7487
return resp.json()
7588
except httpx.HTTPStatusError as e:
89+
logger.info("mcp_tool GET %s %d %s", _safe_path(path), e.response.status_code, client_ip)
7690
return f"Error {e.response.status_code}"
7791
except httpx.HTTPError as e:
92+
logger.info("mcp_tool GET %s err %s", _safe_path(path), client_ip)
7893
return f"Request failed: {e}"
7994

8095

8196
async def _post(path: str, json_body: dict) -> dict | str:
97+
client_ip = _client_ip_var.get() or "unknown"
8298
async with httpx.AsyncClient() as client:
8399
try:
84100
resp = await client.post(
@@ -88,10 +104,13 @@ async def _post(path: str, json_body: dict) -> dict | str:
88104
headers=_headers(),
89105
)
90106
resp.raise_for_status()
107+
logger.info("mcp_tool POST %s %d %s", _safe_path(path), resp.status_code, client_ip)
91108
return resp.json()
92109
except httpx.HTTPStatusError as e:
110+
logger.info("mcp_tool POST %s %d %s", _safe_path(path), e.response.status_code, client_ip)
93111
return f"Error {e.response.status_code}"
94112
except httpx.HTTPError as e:
113+
logger.info("mcp_tool POST %s err %s", _safe_path(path), client_ip)
95114
return f"Request failed: {e}"
96115

97116

0 commit comments

Comments
 (0)