{"title":"SQL Injection","language":"Python","severity":"Critical","cwe":"CWE-89","source_lines":[7,8],"flow_lines":[7,8,9,10],"sink_lines":[10],"vulnerable_code":"from flask import Flask, request\nimport sqlite3\napp = Flask(__name__)\ndef fetch_sensor_telemetry(device_id):\n    conn = sqlite3.connect('iot_hub.db')\n    cur = conn.cursor()\n    threshold = request.args.get('alert_threshold', '50')\n    region = request.args.get('region', 'us-east')\n    qry = \"SELECT sensor_id, reading, timestamp FROM telemetry WHERE device_id='\" + device_id + \"' AND region='\" + region + \"' AND reading > \" + threshold\n    cur.execute(qry)\n    rows = cur.fetchall()\n    conn.close()\n    return rows","explanation":"The HTTP query parameters 'alert_threshold' (line 7) and 'region' (line 8) are retrieved directly from user-controlled request arguments without any sanitization or validation. These untrusted values are then concatenated directly into a raw SQL query string on line 9, and executed on line 10 via cur.execute(qry), enabling a classic SQL injection attack through both a string field (region) and a numeric field (alert_threshold).","remediation":"The fix replaces raw string concatenation with parameterized queries using SQLite's placeholder syntax (?), passing device_id, region, and threshold as bound parameters to cur.execute(). Additionally, the alert_threshold value is validated and cast to a float before use, ensuring that even the numeric field cannot be exploited. This prevents SQL injection across all three input vectors.","secure_code":"from flask import Flask, request\nimport sqlite3\napp = Flask(__name__)\ndef fetch_sensor_telemetry(device_id):\n    conn = sqlite3.connect('iot_hub.db')\n    cur = conn.cursor()\n    threshold = request.args.get('alert_threshold', '50')\n    region = request.args.get('region', 'us-east')\n    # Validate that threshold is a valid number to prevent injection via numeric field\n    try:\n        threshold_val = float(threshold)\n    except (ValueError, TypeError):\n        threshold_val = 50.0\n    qry = \"SELECT sensor_id, reading, timestamp FROM telemetry WHERE device_id=? AND region=? AND reading > ?\"\n    cur.execute(qry, (device_id, region, threshold_val))\n    rows = cur.fetchall()\n    conn.close()\n    return rows"}