# Blind Boolean-Based SQL Injection via String-Concatenated ORM Query

Language: Python
Severity: Critical
CWE: CWE-89

## Source
5

## Flow
5-7-8

## Sink
8

## Vulnerable Code
```python
from flask import request, jsonify
from sqlalchemy import text

def check_iot_device_firmware(db_session):
    device_mac = request.args.get('mac_address', '')
    min_version = request.args.get('min_ver', '1.0')
    query_str = f"SELECT COUNT(*) as cnt FROM iot_devices WHERE mac_address='{device_mac}' AND firmware_version >= '{min_version}'"
    result = db_session.execute(text(query_str)).fetchone()
    if result and result[0] > 0:
        return jsonify({"status": "compliant", "device_found": True})
    else:
        return jsonify({"status": "non_compliant", "device_found": False})
```

## Explanation

User-supplied parameters 'mac_address' and 'min_ver' from request.args are directly concatenated into an SQL query string using f-strings without sanitization or parameterization. This allows attackers to inject malicious SQL code that will be executed by db_session.execute(), enabling blind boolean-based SQL injection through the conditional response structure.

## Remediation

The fix replaces the dangerous f-string SQL concatenation with parameterized queries using SQLAlchemy's named bind parameters (:mac_address and :min_version). The user-supplied values are passed as a separate dictionary to db_session.execute(), ensuring the database driver properly escapes them and prevents SQL injection.

## Secure Code
```python
from flask import request, jsonify
from sqlalchemy import text

def check_iot_device_firmware(db_session):
    device_mac = request.args.get('mac_address', '')
    min_version = request.args.get('min_ver', '1.0')
    query_str = text("SELECT COUNT(*) as cnt FROM iot_devices WHERE mac_address=:mac_address AND firmware_version >= :min_version")
    result = db_session.execute(query_str, {"mac_address": device_mac, "min_version": min_version}).fetchone()
    if result and result[0] > 0:
        return jsonify({"status": "compliant", "device_found": True})
    else:
        return jsonify({"status": "non_compliant", "device_found": False})
```
