{"title":"SQL Injection via f-string Interpolation in sqlite3 Query","language":"Python","severity":"Critical","cwe":"CWE-89","source_lines":[16,18],"flow_lines":[16,18,3,6,7],"sink_lines":[7],"vulnerable_code":"import sqlite3\nimport json\n\ndef retrieve_iot_device_telemetry(device_mac, metric_type, time_range):\n    conn = sqlite3.connect('/var/iot/telemetry.db')\n    cursor = conn.cursor()\n    query = f\"SELECT timestamp, metric_value, unit FROM device_metrics WHERE mac_address = '{device_mac}' AND metric_name = '{metric_type}' AND timestamp >= {time_range} ORDER BY timestamp DESC\"\n    cursor.execute(query)\n    results = cursor.fetchall()\n    telemetry_data = []\n    for row in results:\n        telemetry_data.append({\n            'ts': row[0],\n            'value': row[1],\n            'unit': row[2]\n        })\n    conn.close()\n    return json.dumps(telemetry_data)\n\ndef process_device_query(request_payload):\n    mac = request_payload.get('device_id')\n    metric = request_payload.get('metric')\n    since = request_payload.get('since', '0')\n    return retrieve_iot_device_telemetry(mac, metric, since)","explanation":"The function accepts untrusted user input (device_id, metric, since) from request_payload and passes them directly to retrieve_iot_device_telemetry(), which constructs a SQL query using f-string interpolation without any sanitization or parameterization. This allows attackers to inject arbitrary SQL commands through any of the three parameters.","remediation":"The fix replaces the f-string interpolation in the SQL query with parameterized placeholders (?). The user-supplied values are passed as a tuple to cursor.execute(), which safely binds them as parameters, preventing any injected SQL from being interpreted as code.","secure_code":"import sqlite3\nimport json\n\ndef retrieve_iot_device_telemetry(device_mac, metric_type, time_range):\n    conn = sqlite3.connect('/var/iot/telemetry.db')\n    cursor = conn.cursor()\n    query = \"SELECT timestamp, metric_value, unit FROM device_metrics WHERE mac_address = ? AND metric_name = ? AND timestamp >= ? ORDER BY timestamp DESC\"\n    cursor.execute(query, (device_mac, metric_type, time_range))\n    results = cursor.fetchall()\n    telemetry_data = []\n    for row in results:\n        telemetry_data.append({\n            'ts': row[0],\n            'value': row[1],\n            'unit': row[2]\n        })\n    conn.close()\n    return json.dumps(telemetry_data)\n\ndef process_device_query(request_payload):\n    mac = request_payload.get('device_id')\n    metric = request_payload.get('metric')\n    since = request_payload.get('since', '0')\n    return retrieve_iot_device_telemetry(mac, metric, since)"}