From c75ed4b6da8a72423e5e7299a8d71d66cb059d53 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 8 Feb 2026 10:48:23 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[CRITICAL]?= =?UTF-8?q?=20Fix=20sensitive=20data=20exposure=20in=20logs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🚨 Severity: CRITICAL 💡 Vulnerability: Credentials in URLs (Basic Auth and sensitive query parameters) were logged to stdout/stderr in plain text when using `sanitize_for_log`. 🎯 Impact: Attackers with access to logs could steal credentials or API tokens. 🔧 Fix: Updated `sanitize_for_log` in `main.py` to redact Basic Auth credentials and sensitive query parameters (token, key, secret, password, auth, access_token, api_key). ✅ Verification: Added new test case in `tests/test_log_sanitization.py`. Verified with reproduction script `repro_log_leak.py`. Co-authored-by: abhimehro <84992105+abhimehro@users.noreply.github.com> --- .jules/sentinel.md | 11 +++++++++++ main.py | 13 +++++++++++++ tests/test_log_sanitization.py | 20 ++++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 .jules/sentinel.md diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 00000000..3e31d884 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,11 @@ +## Sentinel's Journal + +This journal documents CRITICAL security learnings found during codebase audits. +Only add entries for: +- Vulnerability patterns specific to this codebase +- Security fixes with unexpected side effects +- Rejected security changes with important constraints +- Surprising security gaps in architecture +- Reusable security patterns for this project + +--- diff --git a/main.py b/main.py index 86792da4..01a9b2a1 100644 --- a/main.py +++ b/main.py @@ -151,6 +151,19 @@ def sanitize_for_log(text: Any) -> str: s = str(text) if TOKEN and TOKEN in s: s = s.replace(TOKEN, "[REDACTED]") + + # Redact Basic Auth in URLs (e.g. https://user:pass@host) + s = re.sub(r"://[^/@]+@", "://[REDACTED]@", s) + + # Redact sensitive query parameters + sensitive_keys = r"token|key|secret|password|auth|access_token|api_key" + s = re.sub( + r"([?&])(" + sensitive_keys + r")=[^&\s]+", + r"\1\2=[REDACTED]", + s, + flags=re.IGNORECASE, + ) + # repr() safely escapes control characters (e.g., \n -> \\n, \x1b -> \\x1b) # This prevents log injection and terminal hijacking. safe = repr(s) diff --git a/tests/test_log_sanitization.py b/tests/test_log_sanitization.py index d8cdcb09..56d8bdfc 100644 --- a/tests/test_log_sanitization.py +++ b/tests/test_log_sanitization.py @@ -67,5 +67,25 @@ def test_create_folder_logs_unsafe_name(self, mock_get, mock_post, mock_sleep, m self.assertTrue(found_sanitized, "Should find sanitized name in logs") self.assertFalse(found_raw, "Should not find raw name in logs") + def test_sanitize_for_log_redacts_credentials(self): + """Test that sanitize_for_log redacts Basic Auth and sensitive query params.""" + # Test Basic Auth + url_with_auth = "https://user:password123@example.com/folder.json" + sanitized = main.sanitize_for_log(url_with_auth) + self.assertNotIn("password123", sanitized) + self.assertIn("[REDACTED]", sanitized) + + # Test Query Params + url_with_param = "https://example.com/folder.json?secret=mysecretkey" + sanitized_param = main.sanitize_for_log(url_with_param) + self.assertNotIn("mysecretkey", sanitized_param) + self.assertIn("[REDACTED]", sanitized_param) + + # Test Case Insensitivity + url_with_token = "https://example.com/folder.json?TOKEN=mytoken" + sanitized_token = main.sanitize_for_log(url_with_token) + self.assertNotIn("mytoken", sanitized_token) + self.assertIn("[REDACTED]", sanitized_token) + if __name__ == '__main__': unittest.main()