{"title":"SHA-1 Length Extension in Homemade MAC Verification","language":"Python","severity":"Critical","cwe":"CWE-327","source_lines":[9],"flow_lines":[9,11],"sink_lines":[11],"vulnerable_code":"import hashlib\n\ndef verify_iot_command(device_id, command, signature, secret_key):\n    expected_sig = hashlib.sha1((secret_key + device_id + command).encode()).hexdigest()\n    if signature == expected_sig:\n        return True\n    return False\n\ndef execute_device_action(device_id, command, signature):\n    SECRET = \"iot_master_key_2024\"\n    if verify_iot_command(device_id, command, signature, SECRET):\n        exec(command)\n        return {\"status\": \"executed\", \"device\": device_id}\n    return {\"status\": \"unauthorized\"}","explanation":"The code uses a homemade MAC scheme with SHA-1 concatenation (secret+data) which is vulnerable to length extension attacks, allowing attackers to append malicious commands without knowing the secret key. Additionally, the exec() function directly executes arbitrary commands without sanitization, enabling command injection once signature validation is bypassed.","remediation":"The fix replaces the vulnerable SHA-1 prefix-based MAC with HMAC-SHA256, which is not susceptible to length extension attacks and uses constant-time comparison via hmac.compare_digest to prevent timing attacks. The dangerous exec() call is replaced with a whitelist of allowed commands mapped to safe handler functions, eliminating arbitrary code execution entirely.","secure_code":"import hmac\nimport hashlib\n\nALLOWED_COMMANDS = {\n    \"status\": lambda device_id: {\"status\": \"online\", \"device\": device_id},\n    \"reboot\": lambda device_id: {\"status\": \"rebooting\", \"device\": device_id},\n    \"shutdown\": lambda device_id: {\"status\": \"shutting_down\", \"device\": device_id},\n    \"get_temperature\": lambda device_id: {\"status\": \"temp_read\", \"device\": device_id},\n    \"toggle_power\": lambda device_id: {\"status\": \"power_toggled\", \"device\": device_id}\n}\n\ndef verify_iot_command(device_id, command, signature, secret_key):\n    message = (device_id + command).encode()\n    expected_sig = hmac.new(secret_key.encode(), message, hashlib.sha256).hexdigest()\n    if hmac.compare_digest(signature, expected_sig):\n        return True\n    return False\n\ndef execute_device_action(device_id, command, signature):\n    SECRET = \"iot_master_key_2024\"\n    if not device_id.isalnum():\n        return {\"status\": \"invalid_device_id\"}\n    command = command.strip()\n    if command not in ALLOWED_COMMANDS:\n        return {\"status\": \"invalid_command\", \"allowed\": list(ALLOWED_COMMANDS.keys())}\n    if verify_iot_command(device_id, command, signature, SECRET):\n        result = ALLOWED_COMMANDS[command](device_id)\n        return {\"status\": \"executed\", \"device\": device_id, \"result\": result}\n    return {\"status\": \"unauthorized\"}"}