{"title":"SQL Injection via String Formatting in SQLite3 execute()","language":"Python","severity":"Critical","cwe":"CWE-89","source_lines":[9],"flow_lines":[9,11],"sink_lines":[11],"vulnerable_code":"import sqlite3\ndef fetch_sensor_telemetry(device_id, metric_type):\n    conn = sqlite3.connect('/var/iot/sensors.db')\n    cur = conn.cursor()\n    query = \"SELECT timestamp, value FROM telemetry WHERE device_id='%s' AND metric='%s'\" % (device_id, metric_type)\n    cur.execute(query)\n    rows = cur.fetchall()\n    conn.close()\n    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":"import sqlite3\ndef fetch_sensor_telemetry(device_id, metric_type):\n    conn = sqlite3.connect('/var/iot/sensors.db')\n    cur = conn.cursor()\n    query = \"SELECT timestamp, value FROM telemetry WHERE device_id=? AND metric=?\"\n    cur.execute(query, (device_id, metric_type))\n    rows = cur.fetchall()\n    conn.close()\n    return [{'ts': r[0], 'val': r[1]} for r in rows]"}