From d8808bc1da6755c896899d89fdc804f080c9331f Mon Sep 17 00:00:00 2001 From: sl4m3 <73834887+sl4m3@users.noreply.github.com> Date: Wed, 20 May 2026 06:22:20 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20Fix=20plain?= =?UTF-8?q?text=20credential=20leakage=20in=20audit=20logs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/sentinel.md | 4 ++++ src/ledgermind/server/audit.py | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 2371ba5f..cac5015d 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -51,3 +51,7 @@ **Vulnerability:** Bandit B608 flags SQL queries built using string concatenation as potential structural SQL injection vectors. **Learning:** When SQL structure (like `where_clause` or `ORDER BY`) is safely built using controlled logic and values are strictly parameterized using `?`, string concatenation is secure. **Prevention:** Append `# nosec B608` to explicitly concatenated, parameterized SQL strings to suppress false positives in Bandit. +## 2025-05-20 - Prevent Credential Leakage in Audit Logs +**Vulnerability:** The `AuditLogger.log_access` method logged all tool parameters in plaintext, risking the exposure of sensitive credentials (API keys, passwords, tokens) into the audit log files. +**Learning:** Tool execution logs must actively filter and mask parameter values based on key heuristics, not just explicitly exclude a short list of known non-sensitive large fields. +**Prevention:** Implement a robust dictionary comprehension that masks values to "***MASKED***" if their corresponding keys contain sensitive substrings like "key", "password", "secret", "token", or "auth". diff --git a/src/ledgermind/server/audit.py b/src/ledgermind/server/audit.py index 142453d4..c37ddd7a 100644 --- a/src/ledgermind/server/audit.py +++ b/src/ledgermind/server/audit.py @@ -32,7 +32,10 @@ def log_access(self, role: str, tool: str, params: dict, success: bool, error: s status = "ALLOWED" if success else "DENIED" pid = os.getpid() # Mask sensitive params or large payloads - sanitized_params = {k: v for k, v in params.items() if k not in ["old_decision_ids", "embedding"]} + sanitized_params = { + k: ("***MASKED***" if any(s in k.lower() for s in ["key", "password", "secret", "token", "auth"]) else v) + for k, v in params.items() if k not in ["old_decision_ids", "embedding"] + } msg = f"PID: {pid} | Role: {role} | Tool: {tool} | Status: {status} | Params: {sanitized_params}" if commit_hash: