# Race Condition in Asyncio Shared-State Updates

Language: Python
Severity: High
CWE: CWE-362

## Source
6

## Flow
6-8-9

## Sink
9

## Vulnerable Code
```python
import asyncio

iot_device_registry = {}

async def provision_iot_device(device_id, firmware_hash, security_key):
    if device_id in iot_device_registry:
        return {"error": "Device already provisioned"}
    await asyncio.sleep(0.05)
    iot_device_registry[device_id] = {
        "firmware": firmware_hash,
        "key": security_key,
        "status": "active"
    }
    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
```python
import asyncio

iot_device_registry = {}
_registry_lock = asyncio.Lock()

async def provision_iot_device(device_id, firmware_hash, security_key):
    async with _registry_lock:
        if device_id in iot_device_registry:
            return {"error": "Device already provisioned"}
        await asyncio.sleep(0.05)
        iot_device_registry[device_id] = {
            "firmware": firmware_hash,
            "key": security_key,
            "status": "active"
        }
        return {"success": f"Device {device_id} provisioned"}
```
