# SQL Injection via f-string in psycopg2.execute

Language: Python
Severity: Critical
CWE: CWE-89

## Source
3

## Flow
3-4-5

## Sink
5

## Vulnerable Code
```python
import psycopg2

def fetch_device_telemetry(conn, device_uuid, metric_type):
    cursor = conn.cursor()
    query = f"SELECT timestamp, value, unit FROM iot_telemetry WHERE device_id = '{device_uuid}' AND metric = '{metric_type}' ORDER BY timestamp DESC LIMIT 100"
    cursor.execute(query)
    telemetry_data = cursor.fetchall()
    cursor.close()
    return telemetry_data

def get_device_metrics(device_id, metric):
    db_conn = psycopg2.connect(database="iot_platform", user="iot_reader", password="sensor123", host="10.0.1.50")
    results = fetch_device_telemetry(db_conn, device_id, metric)
    db_conn.close()
    return results
```

## Explanation

The function uses f-strings to directly interpolate user-controlled parameters (device_uuid and metric_type) into a SQL query string, which is then executed via cursor.execute(). This allows attackers to inject malicious SQL code that will be executed against the database without any sanitization or parameterization.

## Remediation

The fix replaces the vulnerable f-string interpolation with psycopg2's parameterized query mechanism using %s placeholders and passing the parameters as a tuple to cursor.execute(). This ensures that device_uuid and metric_type are properly escaped and treated as data values rather than executable SQL code, preventing any SQL injection attacks.

## Secure Code
```python
import psycopg2

def fetch_device_telemetry(conn, device_uuid, metric_type):
    cursor = conn.cursor()
    query = "SELECT timestamp, value, unit FROM iot_telemetry WHERE device_id = %s AND metric = %s ORDER BY timestamp DESC LIMIT 100"
    cursor.execute(query, (device_uuid, metric_type))
    telemetry_data = cursor.fetchall()
    cursor.close()
    return telemetry_data

def get_device_metrics(device_id, metric):
    db_conn = psycopg2.connect(database="iot_platform", user="iot_reader", password="sensor123", host="10.0.1.50")
    results = fetch_device_telemetry(db_conn, device_id, metric)
    db_conn.close()
    return results
```
