From 6471c540e3c4e749739c2a8214f7c278922f029a Mon Sep 17 00:00:00 2001 From: Jimmy Brancaccio Date: Fri, 25 Sep 2026 17:04:25 -0500 Subject: [PATCH] fix: reduce log-sensitive token false positives --- .../engine/detectors/patterns/security.py | 4 +- .../tests/detectors/security/test_rules.py | 10 +++++ .../tests/detectors/security/test_security.py | 38 +++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/desloppify/engine/detectors/patterns/security.py b/desloppify/engine/detectors/patterns/security.py index 70117c48f..8fa0d2c29 100644 --- a/desloppify/engine/detectors/patterns/security.py +++ b/desloppify/engine/detectors/patterns/security.py @@ -153,8 +153,8 @@ ) SENSITIVE_IN_LOG = re.compile( - r"(?i)(?:password|token|secret|api_key|apikey|credentials|" - r"private_key|access_key|authorization)", + r"(?i)\b(?:password|token|secret|api_key|apikey|credentials|" + r"private_key|access_key|authorization)\b(?=\s*(?:[=:,)}]|$))", ) diff --git a/desloppify/tests/detectors/security/test_rules.py b/desloppify/tests/detectors/security/test_rules.py index a36d8b495..e40d84145 100644 --- a/desloppify/tests/detectors/security/test_rules.py +++ b/desloppify/tests/detectors/security/test_rules.py @@ -104,6 +104,16 @@ def test_sensitive_log_entries_detect_secret_logs(): assert issues[0]["detail"]["kind"] == "log_sensitive" +def test_sensitive_log_entries_ignore_noncredential_token_vocabulary(): + issues = rules_mod._sensitive_log_entries( + filepath="src/report.py", + line_num=12, + line='print(f"{count} token strip(s)")', + ) + + assert issues == [] + + # ── _looks_like_non_secret_value heuristic ──────────────── diff --git a/desloppify/tests/detectors/security/test_security.py b/desloppify/tests/detectors/security/test_security.py index 233a353d1..eff036f72 100644 --- a/desloppify/tests/detectors/security/test_security.py +++ b/desloppify/tests/detectors/security/test_security.py @@ -8,6 +8,8 @@ from pathlib import Path from unittest.mock import patch +import pytest + from desloppify.engine.detectors.security.detector import detect_security_issues from desloppify.engine.policy.zones import FileZoneMap, Zone from desloppify.languages.typescript.detectors.security.detector import detect_ts_security @@ -298,6 +300,42 @@ def test_log_sensitive_console(self): finally: os.unlink(path) + @pytest.mark.parametrize( + "content", + [ + 'print("out tokens")', + 'print(f"{count} token strip(s)")', + 'print(f"folder token(s): {count}")', + 'print(f"folder_token_strip({stem!r})")', + ], + ) + def test_log_sensitive_ignores_noncredential_token_vocabulary(self, content): + path = _write_temp_file(content) + try: + entries, _ = detect_security_issues([path], None, "python") + log_entries = [e for e in entries if e["detail"]["kind"] == "log_sensitive"] + assert log_entries == [] + finally: + os.unlink(path) + + @pytest.mark.parametrize( + "content", + [ + "print(token)", + 'logger.info("%s", credentials)', + 'console.log("api_key=", apiKey);', + ], + ) + def test_log_sensitive_detects_bare_sensitive_values(self, content): + suffix = ".ts" if content.startswith("console") else ".py" + path = _write_temp_file(content, suffix=suffix) + try: + entries, _ = detect_security_issues([path], None, suffix.removeprefix(".")) + log_entries = [e for e in entries if e["detail"]["kind"] == "log_sensitive"] + assert len(log_entries) == 1 + finally: + os.unlink(path) + class TestCrossLangZoneFiltering: def test_generated_zone_skipped(self):