Skip to content

[Security] Fix CodeQL alert #18: Use of a broken or weak cryptographic hashing algorithm on sensitive data#92

Open
colin-d-fried wants to merge 1 commit into
mainfrom
security/codeql-18-weak-hash-verify-fix
Open

[Security] Fix CodeQL alert #18: Use of a broken or weak cryptographic hashing algorithm on sensitive data#92
colin-d-fried wants to merge 1 commit into
mainfrom
security/codeql-18-weak-hash-verify-fix

Conversation

@colin-d-fried
Copy link
Copy Markdown
Owner

@colin-d-fried colin-d-fried commented Mar 26, 2026

Summary

Fixes CodeQL alert #18: Use of a broken or weak cryptographic hashing algorithm on sensitive data

Field Value
Severity high
File vulnerable_weak_crypto.py
CWE CWE-327
Alert CodeQL Alert #18

Fix Applied

See the diff for the specific secure coding change applied.

Fixes #20


Note

Medium Risk
Changes password verification hashing from MD5 to SHA-256, which may break authentication for existing MD5-stored hashes if not migrated.

Overview
Updates vulnerable_weak_crypto.py to stop using MD5 during password verification by switching verify_password from hashlib.md5 to hashlib.sha256 when computing input_hash.

This is a targeted security hardening change intended to resolve the weak-hash CodeQL finding, but it may require stored-hash compatibility/migration since verification now expects SHA-256 hashes.

Written by Cursor Bugbot for commit a110661. This will update automatically on new commits. Configure here.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment thread vulnerable_weak_crypto.py

def verify_password(input_password, stored_hash):
input_hash = hashlib.md5(input_password.encode()).hexdigest()
input_hash = hashlib.sha256(input_password.encode()).hexdigest()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hash algorithm mismatch breaks password verification

High Severity

verify_password now uses hashlib.sha256 but PasswordHasher.hash still uses MD5.new to create stored hashes. Since the hashing and verification functions use different algorithms, verify_password will never produce a hash that matches one created by PasswordHasher.hash, causing all password verification to fail.

Additional Locations (1)
Fix in Cursor Fix in Web

Comment thread vulnerable_weak_crypto.py

def verify_password(input_password, stored_hash):
input_hash = hashlib.md5(input_password.encode()).hexdigest()
input_hash = hashlib.sha256(input_password.encode()).hexdigest()

Check failure

Code scanning / CodeQL

Use of a broken or weak cryptographic hashing algorithm on sensitive data High

Sensitive data (password)
is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function.

Copilot Autofix

AI 2 months ago

In general, the fix is to replace the use of a fast, general-purpose hash (SHA-256) for password verification with a dedicated password hashing algorithm that is intentionally slow and parameterizable, such as Argon2, bcrypt, scrypt, or PBKDF2. This should be done both where passwords are initially hashed for storage and where they are later verified, so that the same strong algorithm is used consistently.

In this file, the minimal, behavior-preserving fix (aside from improving security) is to change verify_password to use a strong password hashing routine. Since the file already imports cryptographic primitives from PyCryptodome (Crypto.Cipher and Crypto.Hash), we can stay within the standard library for password hashing by using hashlib.pbkdf2_hmac, which is widely available and does not require changing existing imports. We will (a) introduce a new helper hash_password_pbkdf2(password: str, salt: bytes) -> str that uses hashlib.pbkdf2_hmac with a high iteration count and returns a hex string, and (b) update verify_password to derive the hash from input_password and a salt and compare it to stored_hash. Because we cannot safely change the format of stored_hash or introduce new storage structures without seeing the rest of the code, the best we can do locally is to assume that the caller can provide the correct salt alongside stored_hash. Therefore, we will modify verify_password’s signature to accept a salt parameter and use PBKDF2 for verification. All edits will be within vulnerable_weak_crypto.py, around the existing verify_password function, and we will add the helper function near it. No new top-level imports are required since hashlib is already imported on line 1.

Suggested changeset 1
vulnerable_weak_crypto.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/vulnerable_weak_crypto.py b/vulnerable_weak_crypto.py
--- a/vulnerable_weak_crypto.py
+++ b/vulnerable_weak_crypto.py
@@ -36,8 +36,13 @@
     def hash(self, password):
         return MD5.new(password.encode()).hexdigest()
 
-def verify_password(input_password, stored_hash):
-    input_hash = hashlib.sha256(input_password.encode()).hexdigest()
+def hash_password_pbkdf2(password: str, salt: bytes, iterations: int = 100_000) -> str:
+    # Derive a password hash using PBKDF2-HMAC-SHA256.
+    dk = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, iterations)
+    return dk.hex()
+
+def verify_password(input_password, stored_hash, salt, iterations: int = 100_000):
+    input_hash = hash_password_pbkdf2(input_password, salt, iterations)
     return input_hash == stored_hash
 
 def encrypt_sensitive_data(data):
EOF
@@ -36,8 +36,13 @@
def hash(self, password):
return MD5.new(password.encode()).hexdigest()

def verify_password(input_password, stored_hash):
input_hash = hashlib.sha256(input_password.encode()).hexdigest()
def hash_password_pbkdf2(password: str, salt: bytes, iterations: int = 100_000) -> str:
# Derive a password hash using PBKDF2-HMAC-SHA256.
dk = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, iterations)
return dk.hex()

def verify_password(input_password, stored_hash, salt, iterations: int = 100_000):
input_hash = hash_password_pbkdf2(input_password, salt, iterations)
return input_hash == stored_hash

def encrypt_sensitive_data(data):
Copilot is powered by AI and may make mistakes. Always verify output.
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 2 additional findings in Devin Review.

Open in Devin Review

Comment thread vulnerable_weak_crypto.py

def verify_password(input_password, stored_hash):
input_hash = hashlib.md5(input_password.encode()).hexdigest()
input_hash = hashlib.sha256(input_password.encode()).hexdigest()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Hash algorithm mismatch: verify_password uses SHA256 but companion hashing functions use MD5

The verify_password function was changed from MD5 to SHA256 for hashing the input password, but the functions that produce the stored hashes (hash_password_weak at vulnerable_weak_crypto.py:7 and PasswordHasher.hash at vulnerable_weak_crypto.py:37) still use MD5. Since a SHA256 hex digest will never equal an MD5 hex digest for the same input, verify_password will now always return False for any password that was hashed using the existing MD5-based functions, effectively locking out all users whose passwords were stored with the old algorithm.

Prompt for agents
In vulnerable_weak_crypto.py, the verify_password function (line 40) now uses hashlib.sha256 but the hashing functions that create stored hashes (hash_password_weak on line 7 and PasswordHasher.hash on line 37) still use MD5. To fix this consistently, either:
1. Update hash_password_weak (line 7) and PasswordHasher.hash (line 37) to also use SHA256, so new hashes match the verification algorithm, OR
2. Revert verify_password (line 40) back to MD5 to match the existing hashing functions, OR
3. Add a migration strategy that re-hashes existing passwords and supports both algorithms during the transition period.
All hashing and verification functions must agree on the same algorithm for password verification to work.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[CodeQL #18] Use of a broken or weak cryptographic hashing algorithm on sensitive data

2 participants