Flask SQL Injection

Critical Risk SQL Injection
sql-injectionflaskpythonweb-framework

What it is

SQL injection vulnerability in Flask applications where user input from form data and query parameters is directly concatenated into SQL queries using f-strings or string formatting without parameterization.

from flask import Flask, request, jsonify
import sqlite3

app = Flask(__name__)

@app.route('/login', methods=['POST'])
def login():
    username = request.form['username']
    password = request.form['password']

    # VULNERABLE: Direct string concatenation
    query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"

    conn = sqlite3.connect('app.db')
    cursor = conn.cursor()
    cursor.execute(query)
    user = cursor.fetchone()
    conn.close()

    if user:
        return jsonify({'status': 'success', 'user_id': user[0]})
    return jsonify({'status': 'failed'})

@app.route('/products')
def get_products():
    category = request.args.get('category', '')
    min_price = request.args.get('min_price', '0')

    # VULNERABLE: String formatting
    query = ("SELECT * FROM products WHERE category = '{}' "
             "AND price >= {}").format(category, min_price)

    conn = sqlite3.connect('app.db')
    cursor = conn.cursor()
    cursor.execute(query)
    products = cursor.fetchall()
    conn.close()

    return jsonify(products)

# Malicious inputs:
# username: admin' OR '1'='1' --
# category: electronics'; DROP TABLE products; --
from flask import Flask, request, jsonify
import sqlite3

app = Flask(__name__)

@app.route('/login', methods=['POST'])
def login():
    username = request.form['username']
    password = request.form['password']

    # SECURE: Parameterized query with ? placeholders
    query = "SELECT * FROM users WHERE username = ? AND password = ?"

    conn = sqlite3.connect('app.db')
    cursor = conn.cursor()
    cursor.execute(query, (username, password))
    user = cursor.fetchone()
    conn.close()

    if user:
        return jsonify({'status': 'success', 'user_id': user[0]})
    return jsonify({'status': 'failed'})

@app.route('/products')
def get_products():
    category = request.args.get('category', '')
    min_price = request.args.get('min_price', '0')

    # SECURE: Parameterized query with ? placeholders
    query = "SELECT * FROM products WHERE category = ? AND price >= ?"

    conn = sqlite3.connect('app.db')
    cursor = conn.cursor()
    cursor.execute(query, (category, min_price))
    products = cursor.fetchall()
    conn.close()

    return jsonify(products)

💡 Why This Fix Works

The vulnerable code uses string concatenation and formatting to build SQL queries with user input. The fixed version uses parameterized queries with ? placeholders and implements proper input validation.

Why it happens

Using f-strings to embed user input directly into SQL queries is a common vulnerability in Flask applications.

Root causes

F-string SQL Injection in Flask Routes

Using f-strings to embed user input directly into SQL queries is a common vulnerability in Flask applications.

Preview example – PYTHON
@app.route('/login', methods=['POST'])
def login():
    username = request.form['username']
    query = f"SELECT * FROM users WHERE username = '{username}'"
    cursor.execute(query)

String Format Method Vulnerabilities

Using .format() method to build SQL queries with user input creates injection vulnerabilities.

Preview example – PYTHON
@app.route('/products')
def get_products():
    category = request.args.get('category')
    query = "SELECT * FROM products WHERE category = '{}'".format(category)

Fixes

1

Use Parameterized Queries with SQLite3

Always use parameterized queries with ? placeholders when working with SQLite3 in Flask applications.

View implementation – PYTHON
@app.route('/login', methods=['POST'])
def login():
    username = request.form.get('username')
    query = "SELECT * FROM users WHERE username = ?"
    cursor.execute(query, (username,))
2

Implement Input Validation Decorators

Create validation decorators to check input types, lengths, and formats before processing Flask requests.

View implementation – PYTHON
def validate_input(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        # Validation logic here
        return f(*args, **kwargs)
    return decorated_function

Detect This Vulnerability in Your Code

Sourcery automatically identifies flask sql injection and many other security issues in your codebase.