{"title":"Race Condition in Asyncio Shared-State Updates","language":"Python","severity":"High","cwe":"CWE-362","source_lines":[6],"flow_lines":[6,8,9],"sink_lines":[9],"vulnerable_code":"import asyncio\n\niot_device_registry = {}\n\nasync def provision_iot_device(device_id, firmware_hash, security_key):\n    if device_id in iot_device_registry:\n        return {\"error\": \"Device already provisioned\"}\n    await asyncio.sleep(0.05)\n    iot_device_registry[device_id] = {\n        \"firmware\": firmware_hash,\n        \"key\": security_key,\n        \"status\": \"active\"\n    }\n    return {\"success\": f\"Device {device_id} provisioned\"}","explanation":"This code contains a race condition vulnerability where the check (line 6) and act (line 9) operations are not atomic. Multiple concurrent calls with the same device_id can all pass the existence check during the asyncio.sleep delay, allowing duplicate registrations that overwrite security keys.","remediation":"The fix introduces an asyncio.Lock that wraps the entire check-then-act sequence, ensuring that the existence check and the registry write are performed atomically. This prevents concurrent coroutines from passing the check simultaneously and overwriting each other's security keys during the await gap.","secure_code":"import asyncio\n\niot_device_registry = {}\n_registry_lock = asyncio.Lock()\n\nasync def provision_iot_device(device_id, firmware_hash, security_key):\n    async with _registry_lock:\n        if device_id in iot_device_registry:\n            return {\"error\": \"Device already provisioned\"}\n        await asyncio.sleep(0.05)\n        iot_device_registry[device_id] = {\n            \"firmware\": firmware_hash,\n            \"key\": security_key,\n            \"status\": \"active\"\n        }\n        return {\"success\": f\"Device {device_id} provisioned\"}"}