{"title":"PostgreSQL SQL Injection via psycopg2 String Interpolation","language":"Python","severity":"Critical","cwe":"CWE-89","source_lines":[10],"flow_lines":[10,11,5],"sink_lines":[5],"vulnerable_code":"import psycopg2\n\ndef fetch_iot_device_telemetry(conn, device_mac, metric_type):\n    cursor = conn.cursor()\n    query = \"SELECT timestamp, value, unit FROM sensor_data WHERE device_mac='%s' AND metric='%s' ORDER BY timestamp DESC LIMIT 100\" % (device_mac, metric_type)\n    cursor.execute(query)\n    telemetry_records = cursor.fetchall()\n    cursor.close()\n    return telemetry_records\n\ndef get_device_metrics(db_config, mac_address, sensor_metric):\n    connection = psycopg2.connect(**db_config)\n    results = fetch_iot_device_telemetry(connection, mac_address, sensor_metric)\n    connection.close()\n    return results","explanation":"The code uses Python string formatting (%) to directly interpolate user-controlled parameters (device_mac, metric_type) into a SQL query string without any sanitization or parameterization. This allows attackers to inject arbitrary SQL commands by crafting malicious input that breaks out of the string context.","remediation":"The fix replaces unsafe Python string formatting (% operator) with psycopg2's built-in parameterized query mechanism. By passing user-supplied values (device_mac, metric_type) as a tuple in the second argument to cursor.execute(), psycopg2 handles proper escaping and type conversion, completely preventing SQL injection regardless of input content.","secure_code":"import psycopg2\n\ndef fetch_iot_device_telemetry(conn, device_mac, metric_type):\n    cursor = conn.cursor()\n    query = \"SELECT timestamp, value, unit FROM sensor_data WHERE device_mac=%s AND metric=%s ORDER BY timestamp DESC LIMIT 100\"\n    cursor.execute(query, (device_mac, metric_type))\n    telemetry_records = cursor.fetchall()\n    cursor.close()\n    return telemetry_records\n\ndef get_device_metrics(db_config, mac_address, sensor_metric):\n    connection = psycopg2.connect(**db_config)\n    results = fetch_iot_device_telemetry(connection, mac_address, sensor_metric)\n    connection.close()\n    return results"}