{"title":"Race Condition in File Creation via os.path.exists() TOCTOU","language":"Python","severity":"High","cwe":"CWE-367","source_lines":[7],"flow_lines":[7,8,9,10],"sink_lines":[8],"vulnerable_code":"import os\nimport json\n\ndef provision_iot_device_certificate(device_id, cert_data):\n    cert_dir = '/var/iot/device_certs'\n    cert_path = os.path.join(cert_dir, f'{device_id}.pem')\n    if not os.path.exists(cert_path):\n        with open(cert_path, 'w') as cert_file:\n            cert_file.write(cert_data)\n        os.chmod(cert_path, 0o600)\n        return {'status': 'provisioned', 'device': device_id, 'cert_path': cert_path}\n    else:\n        return {'status': 'already_exists', 'device': device_id}","explanation":"The code suffers from a Time-of-Check Time-of-Use (TOCTOU) race condition. Between checking if the file exists (line 7) and creating it (line 8), an attacker could create a symlink at that path pointing to a sensitive file, causing the certificate data to overwrite the target file with attacker-controlled device_id in the path.","remediation":"The fix eliminates the TOCTOU race condition by using os.open() with O_CREAT | O_EXCL | O_NOFOLLOW flags, which atomically creates the file only if it doesn't already exist and refuses to follow symlinks. Additionally, input validation on device_id prevents path traversal attacks, and the file permissions are set atomically at creation time via the mode parameter to os.open(), removing the need for a separate chmod call.","secure_code":"import os\nimport json\nimport re\n\ndef provision_iot_device_certificate(device_id, cert_data):\n    cert_dir = '/var/iot/device_certs'\n    \n    # Validate device_id to prevent path traversal\n    if not re.match(r'^[a-zA-Z0-9_\\-]+$', device_id):\n        return {'status': 'error', 'device': device_id, 'message': 'Invalid device_id'}\n    \n    cert_path = os.path.join(cert_dir, f'{device_id}.pem')\n    \n    # Verify the resolved path is within the expected directory\n    real_cert_dir = os.path.realpath(cert_dir)\n    # Use os.path.normpath to check intended path stays within cert_dir\n    if not os.path.normpath(cert_path).startswith(real_cert_dir + os.sep):\n        return {'status': 'error', 'device': device_id, 'message': 'Path traversal detected'}\n    \n    # Use O_CREAT | O_EXCL | O_WRONLY to atomically create the file only if it doesn't exist\n    # O_NOFOLLOW prevents following symlinks\n    try:\n        fd = os.open(cert_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY | os.O_NOFOLLOW, 0o600)\n    except FileExistsError:\n        return {'status': 'already_exists', 'device': device_id}\n    except OSError as e:\n        return {'status': 'error', 'device': device_id, 'message': str(e)}\n    \n    try:\n        with os.fdopen(fd, 'w') as cert_file:\n            cert_file.write(cert_data)\n    except Exception:\n        # Clean up on write failure\n        os.unlink(cert_path)\n        raise\n    \n    return {'status': 'provisioned', 'device': device_id, 'cert_path': cert_path}"}