Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion vulnerable_weak_crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
return MD5.new(password.encode()).hexdigest()

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

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

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.

return input_hash == stored_hash

def encrypt_sensitive_data(data):
Expand Down
Loading