{"title":"SQL Injection","language":"Python","severity":"Critical","cwe":"CWE-89","source_lines":[14],"flow_lines":[14,13,4,7,8],"sink_lines":[8],"vulnerable_code":"from flask import Flask, request\nimport sqlite3\napp = Flask(__name__)\ndef fetch_iot_telemetry(device_filter):\n    conn = sqlite3.connect('iot_hub.db')\n    cur = conn.cursor()\n    qry = \"SELECT dev_id, payload, ts FROM telemetry WHERE region='\" + device_filter + \"' ORDER BY ts DESC\"\n    cur.execute(qry)\n    rows = cur.fetchall()\n    conn.close()\n    return rows\n@app.route('/api/telemetry')\ndef telemetry_endpoint():\n    region = request.args.get('region', 'us-east')\n    return str(fetch_iot_telemetry(region))","explanation":"The 'region' parameter is retrieved directly from the HTTP query string on line 14 without any sanitization or validation. It is passed into fetch_iot_telemetry() and concatenated directly into a raw SQL string on line 7, then executed on line 8 via cur.execute(qry), allowing an attacker to manipulate the SQL query structure.","remediation":"The fix replaces the vulnerable string concatenation in the SQL query with a parameterized query using a placeholder ('?') and passes the user input as a bound parameter tuple to cur.execute(). This ensures the database driver treats the input strictly as data, never as executable SQL. Additionally, an allowlist of valid regions and a strict regex validation are applied at the endpoint level to reject malicious or unexpected input before it ever reaches the database layer.","secure_code":"from flask import Flask, request, jsonify\nimport sqlite3\nimport re\n\napp = Flask(__name__)\n\nALLOWED_REGIONS = {'us-east', 'us-west', 'eu-west', 'eu-central', 'ap-south', 'ap-northeast'}\n\ndef fetch_iot_telemetry(device_filter):\n    conn = sqlite3.connect('iot_hub.db')\n    cur = conn.cursor()\n    qry = \"SELECT dev_id, payload, ts FROM telemetry WHERE region=? ORDER BY ts DESC\"\n    cur.execute(qry, (device_filter,))\n    rows = cur.fetchall()\n    conn.close()\n    return rows\n\n@app.route('/api/telemetry')\ndef telemetry_endpoint():\n    region = request.args.get('region', 'us-east')\n    if region not in ALLOWED_REGIONS:\n        if not re.fullmatch(r'[a-zA-Z0-9\\-]{1,30}', region):\n            return jsonify({'error': 'Invalid region parameter'}), 400\n    return jsonify({'telemetry': fetch_iot_telemetry(region)})"}