From 26045dd18794204dffbbf45fec923809e222ee34 Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Mon, 13 Jul 2026 13:22:28 +0100 Subject: [PATCH] fix(security): drop credential key_id from AZ-IDN-006 debug logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit app_id/key_id are Azure AD identifiers, not the secret value itself (Microsoft Graph never returns password credential secret text after creation) — but key_id isn't needed to diagnose a malformed endDateTime either way, so drop it from the log line rather than argue the classification. Fixes #178 (CodeQL: clear-text logging of sensitive information, both findings — same log statement). --- scanner/rules/az_idn_006.py | 3 +-- tests/test_rules_identity.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/scanner/rules/az_idn_006.py b/scanner/rules/az_idn_006.py index 99e9d4a..9a8065a 100644 --- a/scanner/rules/az_idn_006.py +++ b/scanner/rules/az_idn_006.py @@ -87,9 +87,8 @@ def scan(azure_client: Any, subscription_id: str) -> List[Dict[str, Any]]: already_expired = end_dt < now except ValueError: logger.debug( - "AZ-IDN-006: Invalid endDateTime for app_id=%s key_id=%s: %r", + "AZ-IDN-006: Invalid endDateTime for app_id=%s: %r", app_id, - key_id, end_dt_str, ) diff --git a/tests/test_rules_identity.py b/tests/test_rules_identity.py index 10321ae..18be4ef 100644 --- a/tests/test_rules_identity.py +++ b/tests/test_rules_identity.py @@ -288,6 +288,38 @@ def test_idn_006_noncompliant_secret_no_expiry_returns_finding(mock_azure, subsc assert findings[0]["metadata"]["no_expiry"] is True +def test_idn_006_malformed_end_date_time_does_not_log_key_id(mock_azure, subscription_id, monkeypatch, caplog): + """CodeQL: clear-text logging of sensitive information. keyId is a Graph + API credential-slot identifier (not the secret itself), but the debug log + for a malformed endDateTime must not include it regardless — the value + isn't needed to diagnose a date-parsing failure.""" + sentinel_key_id = "sentinel-key-id-should-not-appear-in-logs" + apps = { + "value": [ + { + "id": "app1", + "displayName": "App One", + "appId": "client-1", + "passwordCredentials": [ + { + "keyId": sentinel_key_id, + "hint": "ab", + "startDateTime": "2020-01-01T00:00:00Z", + "endDateTime": "not-a-valid-date", + } + ], + } + ] + } + _install_router(monkeypatch, [("/applications", _Resp(apps))]) + with caplog.at_level("DEBUG", logger="scanner.rules.az_idn_006"): + findings = az_idn_006.scan(mock_azure, subscription_id) + + # Malformed endDateTime alone doesn't matter here: the secret is already stale by age. + assert len(findings) == 1 + assert sentinel_key_id not in caplog.text + + # ── AZ-IDN-007: active user with no MFA registered ──────────────────────────