{"title":"Race Condition via TOCTOU in Temporary File Creation","language":"Python","severity":"High","cwe":"CWE-367","source_lines":[5],"flow_lines":[5,6,7],"sink_lines":[7],"vulnerable_code":"import os\nimport tempfile\ndef store_iot_telemetry(device_id, payload):\n    tmp_dir = tempfile.gettempdir()\n    sensor_file = os.path.join(tmp_dir, f'sensor_{device_id}.dat')\n    if not os.path.exists(sensor_file):\n        with open(sensor_file, 'w') as fh:\n            fh.write(payload)\n        os.chmod(sensor_file, 0o644)\n        return sensor_file\n    return None","explanation":"The code constructs a predictable temporary file path using a device_id (line 5), then performs a TOCTOU (Time-Of-Check-Time-Of-Use) race: it checks if the file exists (line 6) and then opens/writes to it (line 7). Between the os.path.exists() check and the open() call, an attacker can create a symbolic link at the target path (e.g., /tmp/sensor_<device_id>.dat -> /etc/cron.d/backdoor), causing the service to write attacker-influenced payload data to an arbitrary privileged file.","remediation":"The fix replaces the TOCTOU-vulnerable check-then-act pattern (os.path.exists followed by open) with tempfile.mkstemp(), which atomically creates and opens a new unique temporary file with a secure file descriptor, eliminating the race window. The file descriptor is immediately wrapped with os.fdopen to write the payload, preventing any symlink attack between check and use. Additionally, permissions are tightened from 0o644 to 0o600 to restrict access to only the owning process.","secure_code":"import os\nimport tempfile\ndef store_iot_telemetry(device_id, payload):\n    tmp_dir = tempfile.gettempdir()\n    prefix = f'sensor_{device_id}_'\n    try:\n        fd = tempfile.mkstemp(prefix=prefix, suffix='.dat', dir=tmp_dir)\n        file_descriptor, sensor_file = fd\n        with os.fdopen(file_descriptor, 'w') as fh:\n            fh.write(payload)\n        os.chmod(sensor_file, 0o600)\n        return sensor_file\n    except OSError:\n        return None"}