-
Notifications
You must be signed in to change notification settings - Fork 18
repr() quoting of return values breaks secret-in-log scanner detection #382
Description
Summary
When APPMAP_DISPLAY_PARAMS=true is set, the Python agent uses repr() to serialize parameter and return values. For strings, this wraps the value in single quotes — e.g. a function returning my-api-key is recorded as 'my-api-key'.
The AppMap scanner's secret-in-log rule uses substring matching to detect when a secret-labeled function's return value appears inside a log-labeled function's parameters. Because repr() adds quotes around the secret return value, but the secret appears unquoted when interpolated into a larger f-string log message, the substring match fails.
Reproduction
Given:
from _appmap.labels import labels
@labels("secret")
def signoz_api_key() -> str:
return os.environ.get("SIGNOZ_API_KEY", "")
@labels("log")
def log(message: str, *, level: str = "info"):
print(f"[{level}] {message}", file=sys.stderr)
def init():
api_key = signoz_api_key()
log(f"SigNoz configured: api_key={api_key}") # secret leaked into logWith APPMAP_DISPLAY_PARAMS=true, the recorded events contain:
- Secret return value:
'snz-k8v2xQ9mP4wR7jL1nT6y'(with repr quotes) - Log parameter:
'SigNoz configured: api_key=snz-k8v2xQ9mP4wR7jL1nT6y'(with outer repr quotes)
The scanner checks logParam.includes(secretReturnValue):
"'SigNoz configured: api_key=snz-k8v2xQ9mP4wR7jL1nT6y'".includes("'snz-k8v2xQ9mP4wR7jL1nT6y'")
// → false, because the leading quote of the secret doesn't match (preceded by `=` not `'`)
Expected behavior
The scanner should detect that the secret value snz-k8v2xQ9mP4wR7jL1nT6y appears in the log message, regardless of repr() quoting.
Suggested fix
Strip surrounding quotes from string values before recording them as secrets or before the substring comparison. In _appmap/event.py, the display_string() function could strip the repr() quotes for string types, or the agent could record a separate raw_value field without repr() wrapping for use by downstream tools.
Alternatively, this could be addressed in the scanner (recordSecrets.ts / secretInLog.ts) by stripping quotes from the parsed secret values before comparison.
Environment
- appmap-python: latest (tested via pip install)
- appmap-scanner: 1.89.1
- Python: 3.13
APPMAP_DISPLAY_PARAMS=truerequired to reproduce (without it, values are opaque object references and no detection is possible at all)