{"title":"Insecure Temporary File Creation via Predictable Filename and Symlink Attack","language":"Python","severity":"High","cwe":"CWE-377","source_lines":[3],"flow_lines":[3,4,6,3,4,10],"sink_lines":[6,10],"vulnerable_code":"import os\nimport time\n\ndef export_iot_device_logs(device_id, log_data):\n    timestamp = int(time.time())\n    temp_log_path = f\"/tmp/iot_device_{device_id}_{timestamp}.log\"\n    if os.path.exists(temp_log_path):\n        os.remove(temp_log_path)\n    with open(temp_log_path, 'w') as log_file:\n        log_file.write(f\"Device ID: {device_id}\\n\")\n        log_file.write(f\"Timestamp: {timestamp}\\n\")\n        log_file.write(log_data)\n    os.system(f\"gzip {temp_log_path}\")\n    return f\"{temp_log_path}.gz\"","explanation":"The code creates temporary files with predictable names using timestamp and user-controlled device_id. An attacker can predict the filename and create a symlink at that location, causing the application to write sensitive log data to an attacker-controlled file or overwrite critical system files. The os.system() call also introduces command injection risk if device_id contains shell metacharacters.","remediation":"The fix uses tempfile.mkdtemp() and tempfile.mkstemp() for secure, atomic temporary file creation that eliminates race conditions and symlink attacks. Device ID is validated with a strict regex whitelist to prevent command injection. The os.system() call is replaced with subprocess.run() using an argument list to avoid shell interpretation of special characters.","secure_code":"import os\nimport tempfile\nimport subprocess\nimport re\nimport shutil\n\ndef export_iot_device_logs(device_id, log_data):\n    # Validate device_id to prevent injection attacks\n    if not re.match(r'^[a-zA-Z0-9_-]+$', str(device_id)):\n        raise ValueError(\"Invalid device_id: must contain only alphanumeric characters, hyphens, and underscores\")\n    \n    # Create a secure temporary directory with restricted permissions\n    secure_tmp_dir = tempfile.mkdtemp(prefix='iot_logs_')\n    try:\n        os.chmod(secure_tmp_dir, 0o700)\n        \n        # Use mkstemp for secure temporary file creation (atomic, no race condition)\n        fd, temp_log_path = tempfile.mkstemp(\n            prefix=f'iot_device_{device_id}_',\n            suffix='.log',\n            dir=secure_tmp_dir\n        )\n        \n        try:\n            # Write data using the file descriptor to avoid TOCTOU race\n            with os.fdopen(fd, 'w') as log_file:\n                log_file.write(f\"Device ID: {device_id}\\n\")\n                log_file.write(f\"Timestamp: {os.path.basename(temp_log_path)}\\n\")\n                log_file.write(log_data)\n            \n            # Use subprocess with argument list to avoid shell injection\n            compressed_path = f\"{temp_log_path}.gz\"\n            result = subprocess.run(\n                ['gzip', temp_log_path],\n                capture_output=True,\n                check=True\n            )\n            return compressed_path\n        except Exception:\n            # Clean up the file descriptor if writing fails\n            if os.path.exists(temp_log_path):\n                os.unlink(temp_log_path)\n            raise\n    except Exception:\n        # Clean up temporary directory on failure\n        shutil.rmtree(secure_tmp_dir, ignore_errors=True)\n        raise"}