fix: prevent telemetry from leaking API keys in logs

Prevent sensitive API keys from being logged in telemetry output by
masking values that start with known API key prefixes (sk-, AIza) or
appear as long alphanumeric strings. This ensures that OpenAI,
Anthropic, Google, and other provider API keys are never exposed.

I don't know the definition of all possible API key so I'm not claiming
full coverage :).

Signed-off-by: Sébastien Han <seb@redhat.com>
This commit is contained in:
Sébastien Han 2025-08-08 15:54:45 +02:00
parent e90fe25890
commit 143cb85cbd
No known key found for this signature in database

View file

@ -16,6 +16,29 @@ from llama_stack.log import get_logger
logger = get_logger(name="console_span_processor", category="telemetry") logger = get_logger(name="console_span_processor", category="telemetry")
def _mask_sensitive_value(value: str) -> str:
"""Mask sensitive information like API keys in string values."""
# These should cover OpenAI, Anthropic, Google at least
api_key_prefixes = [
"sk-", # OpenAI, Anthropic
"AIza", # Google
]
for prefix in api_key_prefixes:
if value.startswith(prefix):
logger.debug("Masking potentially sensitive API key value")
return "********"
# Also check for long alphanumeric strings that might be API keys
# This is best effort, as it's not always possible to determine if a string is an API key from a
# known prefix.
if len(value) >= 32 and value.isalnum():
logger.debug("Masking potentially sensitive long alphanumeric API key value")
return "********"
return value
class ConsoleSpanProcessor(SpanProcessor): class ConsoleSpanProcessor(SpanProcessor):
def __init__(self, print_attributes: bool = False): def __init__(self, print_attributes: bool = False):
self.print_attributes = print_attributes self.print_attributes = print_attributes
@ -43,6 +66,7 @@ class ConsoleSpanProcessor(SpanProcessor):
if key.startswith("__"): if key.startswith("__"):
continue continue
str_value = str(value) str_value = str(value)
str_value = _mask_sensitive_value(str_value)
if len(str_value) > 1000: if len(str_value) > 1000:
str_value = str_value[:997] + "..." str_value = str_value[:997] + "..."
logger.info(f" [dim]{key}[/dim]: {str_value}") logger.info(f" [dim]{key}[/dim]: {str_value}")
@ -64,7 +88,10 @@ class ConsoleSpanProcessor(SpanProcessor):
for key, value in event.attributes.items(): for key, value in event.attributes.items():
if key.startswith("__") or key in ["message", "severity"]: if key.startswith("__") or key in ["message", "severity"]:
continue continue
logger.info(f"[dim]{key}[/dim]: {value}")
str_value = str(value)
str_value = _mask_sensitive_value(str_value)
logger.info(f"[dim]{key}[/dim]: {str_value}")
def shutdown(self) -> None: def shutdown(self) -> None:
"""Shutdown the processor.""" """Shutdown the processor."""