{"title":"SQL Injection via sqlite3.executescript() on Untrusted Input","language":"Python","severity":"Critical","cwe":"CWE-89","source_lines":[3],"flow_lines":[3,6,8],"sink_lines":[8],"vulnerable_code":"import sqlite3\n\ndef purge_expired_iot_telemetry(device_mac, retention_days):\n    conn = sqlite3.connect('/var/iot/telemetry.db')\n    cursor = conn.cursor()\n    cleanup_script = f\"\"\"\n    DELETE FROM sensor_data WHERE device_id = '{device_mac}' AND timestamp < datetime('now', '-{retention_days} days');\n    VACUUM;\n    \"\"\"\n    cursor.executescript(cleanup_script)\n    conn.commit()\n    conn.close()\n    return f\"Cleaned telemetry for {device_mac}\"","explanation":"The function accepts untrusted input parameters (device_mac, retention_days) and directly interpolates them into an SQL script using f-strings without any sanitization or parameterization. The executescript() method then executes this dynamically constructed SQL, allowing an attacker to inject arbitrary SQL commands through either parameter.","remediation":"The fix replaces the dangerous f-string interpolation and executescript() call with parameterized queries using cursor.execute() with placeholder parameters (?). Additionally, input validation is added to ensure device_mac matches a valid MAC address format and retention_days is a positive integer, providing defense-in-depth against injection attacks.","secure_code":"import sqlite3\nimport re\n\ndef purge_expired_iot_telemetry(device_mac, retention_days):\n    # Validate device_mac format (MAC address pattern)\n    if not re.match(r'^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$', device_mac):\n        raise ValueError(\"Invalid MAC address format\")\n    \n    # Validate retention_days is a positive integer\n    retention_days = int(retention_days)\n    if retention_days <= 0:\n        raise ValueError(\"Retention days must be a positive integer\")\n    \n    conn = sqlite3.connect('/var/iot/telemetry.db')\n    cursor = conn.cursor()\n    \n    # Use parameterized query for the DELETE statement\n    cursor.execute(\n        \"DELETE FROM sensor_data WHERE device_id = ? AND timestamp < datetime('now', ?)\",\n        (device_mac, f'-{retention_days} days')\n    )\n    \n    conn.commit()\n    \n    # VACUUM must be run separately and doesn't involve user input\n    cursor.execute(\"VACUUM\")\n    \n    conn.close()\n    return f\"Cleaned telemetry for {device_mac}\""}