diff --git a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql index 1e7b4452a9a6..a8deaafca0b3 100644 --- a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql +++ b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql @@ -64,7 +64,9 @@ predicate maybeCredential(ControlFlowNode f) { ) and not possible_reflective_name(str.getText()) and not capitalized_word(str) and - not format_string(str) + not format_string(str) and + /* Not a dotted Python module/class path (e.g., "django.contrib.auth.hashers.PBKDF2PasswordHasher") */ + not str.getText().regexpMatch("[a-zA-Z_][a-zA-Z0-9_]*(\\.[a-zA-Z_][a-zA-Z0-9_]*){2,}") ) or /* Or, an integer with over 32 bits */ diff --git a/python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/test_module_paths.py b/python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/test_module_paths.py new file mode 100644 index 000000000000..fe4f5b1ee863 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/test_module_paths.py @@ -0,0 +1,22 @@ +# Test that dotted module/class paths are not flagged as hardcoded credentials. +# These are commonly used in Django settings for PASSWORD_HASHERS, backends, etc. + +PASSWORD_HASHERS = [ + "django.contrib.auth.hashers.PBKDF2PasswordHasher", + "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", + "django.contrib.auth.hashers.Argon2PasswordHasher", +] + +AUTHENTICATION_BACKENDS = [ + "django.contrib.auth.backends.ModelBackend", + "allauth.account.auth_backends.AuthenticationBackend", +] + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", +] + +# This should still be flagged - actual credential +def connect(): + client.connect(password="s3cr3t_passw0rd_12345") # this is a real credential