# SQL Injection via String Formatting in SQLite3 execute()

Language: Python
Severity: Critical
CWE: CWE-89

## Source
9

## Flow
9-11

## Sink
11

## Vulnerable Code
```python
import sqlite3
def fetch_sensor_telemetry(device_id, metric_type):
    conn = sqlite3.connect('/var/iot/sensors.db')
    cur = conn.cursor()
    query = "SELECT timestamp, value FROM telemetry WHERE device_id='%s' AND metric='%s'" % (device_id, metric_type)
    cur.execute(query)
    rows = cur.fetchall()
    conn.close()
    return [{'ts': r[0], 'val': r[1]} for r in rows]
```

## Explanation

The function accepts `device_id` and `metric_type` directly from caller input and interpolates them into a raw SQL string using Python's `%` string formatting on line 5. This tainted string is then passed directly to `cur.execute()` on line 6 without parameterization, allowing an attacker to break out of the string literals and inject arbitrary SQL logic.

## Remediation

The fix replaces the unsafe `%` string formatting with SQLite3's built-in parameterized query mechanism using `?` placeholders. The `device_id` and `metric_type` values are now passed as a tuple in the second argument to `cur.execute()`, which ensures they are properly escaped and treated as literal data values rather than executable SQL, completely preventing SQL injection.

## Secure Code
```python
import sqlite3
def fetch_sensor_telemetry(device_id, metric_type):
    conn = sqlite3.connect('/var/iot/sensors.db')
    cur = conn.cursor()
    query = "SELECT timestamp, value FROM telemetry WHERE device_id=? AND metric=?"
    cur.execute(query, (device_id, metric_type))
    rows = cur.fetchall()
    conn.close()
    return [{'ts': r[0], 'val': r[1]} for r in rows]
```
