{"title":"Weak Password Hashing via unsalted MD5 in hashlib.md5()","language":"Python","severity":"High","cwe":"CWE-328","source_lines":[7],"flow_lines":[7,11],"sink_lines":[11],"vulnerable_code":"import hashlib\nimport boto3\n\ndef provision_iot_device_credentials(device_mac, admin_pin):\n    dynamodb = boto3.resource('dynamodb', region_name='us-east-1')\n    device_table = dynamodb.Table('IoTDeviceRegistry')\n    hashed_pin = hashlib.md5(admin_pin.encode()).hexdigest()\n    device_table.put_item(\n        Item={\n            'device_id': device_mac,\n            'admin_credential': hashed_pin,\n            'provisioned_at': str(datetime.now()),\n            'status': 'active'\n        }\n    )\n    return {'device_id': device_mac, 'credential_hash': hashed_pin}","explanation":"The code uses MD5 hashing without salt to hash admin PINs before storing them in DynamoDB. MD5 is cryptographically broken and allows attackers to use rainbow tables or precomputed hash databases to reverse the hashes and retrieve original PINs, especially since PINs are typically short numeric values.","remediation":"The fix replaces the insecure unsalted MD5 hash with bcrypt, a purpose-built password hashing algorithm that automatically generates and incorporates a unique salt and uses a configurable work factor (rounds=12) to make brute-force attacks computationally expensive. Additionally, the credential hash is no longer returned in the response to avoid unnecessary exposure of sensitive data.","secure_code":"import bcrypt\nimport boto3\nfrom datetime import datetime\n\ndef provision_iot_device_credentials(device_mac, admin_pin):\n    dynamodb = boto3.resource('dynamodb', region_name='us-east-1')\n    device_table = dynamodb.Table('IoTDeviceRegistry')\n    salt = bcrypt.gensalt(rounds=12)\n    hashed_pin = bcrypt.hashpw(admin_pin.encode(), salt).decode('utf-8')\n    device_table.put_item(\n        Item={\n            'device_id': device_mac,\n            'admin_credential': hashed_pin,\n            'provisioned_at': str(datetime.now()),\n            'status': 'active'\n        }\n    )\n    return {'device_id': device_mac, 'status': 'provisioned'}"}