# TOCTOU Race Condition in Temporary File Handling

Language: Python
Severity: High
CWE: CWE-367

## Source
8

## Flow
8-9-12

## Sink
9, 12

## Vulnerable Code
```python
import os
import tempfile
import json

def store_iot_device_credentials(device_id, api_key, secret_token):
    temp_dir = tempfile.gettempdir()
    cred_file = os.path.join(temp_dir, f"iot_device_{device_id}.json")
    if not os.path.exists(cred_file):
        with open(cred_file, 'w') as f:
            credentials = {"device_id": device_id, "api_key": api_key, "secret": secret_token, "provisioned": True}
            json.dump(credentials, f)
        os.chmod(cred_file, 0o600)
        return f"Credentials stored securely for device {device_id}"
    else:
        return "Device already provisioned"
```

## Explanation

The code exhibits a Time-of-Check to Time-of-Use (TOCTOU) race condition. Between the os.path.exists() check (line 8) and the file creation (line 9), an attacker can create a symbolic link or malicious file at that path, causing sensitive credentials to be written to an attacker-controlled location. Additionally, chmod is applied after writing data (line 12), creating another exploitable window where credentials are temporarily world-readable.

## Remediation

The fix uses os.open() with O_CREAT | O_EXCL flags to atomically check for file existence and create the file in a single system call, eliminating the TOCTOU race window. The file permissions (0o600) are set at creation time rather than after writing, ensuring credentials are never world-readable. O_EXCL also refuses to follow symbolic links, preventing symlink attacks.

## Secure Code
```python
import os
import tempfile
import json

def store_iot_device_credentials(device_id, api_key, secret_token):
    temp_dir = tempfile.gettempdir()
    cred_file = os.path.join(temp_dir, f"iot_device_{device_id}.json")
    try:
        fd = os.open(cred_file, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
    except FileExistsError:
        return "Device already provisioned"
    try:
        with os.fdopen(fd, 'w') as f:
            credentials = {"device_id": device_id, "api_key": api_key, "secret": secret_token, "provisioned": True}
            json.dump(credentials, f)
    except Exception:
        os.close(fd)
        raise
    return f"Credentials stored securely for device {device_id}"
```
