Sql Injection in Flask with Basic Auth
Sql Injection in Flask with Basic Auth — how this specific combination creates or exposes the vulnerability
SQL injection in a Flask route that uses HTTP Basic Authentication arises when user-controlled input—such as a username or password parameter—is concatenated into SQL strings without proper validation or parameterization. Even though Basic Auth transmits credentials in base64 (not encryption), the server-side code must still treat the decoded username and password as untrusted input. Consider a typical pattern where the client sends an Authorization header, the server decodes it, and then uses the username to look up a user record:
username_b64, password_b64 = request.headers.get('Authorization', '').split(' ')[1].split(':')
username = base64.b64decode(username_b64).decode('utf-8')
password = base64.b64decode(password_b64).decode('utf-8')
If these values are later used in a query like cursor.execute("SELECT * FROM users WHERE username = '...' AND password = '..."), an attacker who can control the decoded username or password may inject SQL. Common techniques include adding ' OR '1'='1 to the username or password, or leveraging authentication endpoints that do not enforce strict input validation. The risk is compounded when the same endpoint also exposes additional logic, such as dynamic role or tenant selection, where an attacker might leverage tautologies to bypass authentication entirely or extract sensitive data.
Another scenario involves using the authenticated identity in administrative or lookup flows, for example to fetch user-specific configuration or audit logs. If the application builds queries using string formatting or concatenation—such as f"SELECT * FROM settings WHERE user_id = {user_id}"—the attacker may manipulate the authenticated username to change the interpreted user_id or inject a UNION-based payload to exfiltrate credentials or session tokens from other tables. Even if the Basic Auth credentials themselves are validated via a safe ORM, downstream queries that reuse the decoded identity remain vulnerable when they deviate from parameterized patterns. Because the authentication step does not inherently sanitize or parameterize later SQL usage, the combination of Basic Auth and dynamic SQL creates a clear path for unauthorized data access or privilege escalation.
Finally, attackers may probe for SQL injection on authentication routes using automated tools once they observe that the endpoint accepts and processes Basic Auth headers. The presence of Basic Auth does not reduce the need for secure coding practices; in fact, it increases the importance of parameterization because the decoded credentials are high-value targets. Proper remediation involves treating all inputs derived from the Authorization header as untrusted, using parameterized queries or prepared statements, and avoiding any direct interpolation of decoded values into SQL strings.
Basic Auth-Specific Remediation in Flask — concrete code fixes
To mitigate SQL injection when using Basic Auth in Flask, always use parameterized queries or an ORM, and avoid building SQL by string formatting. Below are concrete, working code examples that demonstrate secure handling of decoded credentials.
Insecure example to avoid:
import base64
from flask import request, jsonify
import sqlite3
@app.route('/profile')
def profile():
auth = request.headers.get('Authorization', '')
if auth.startswith('Basic '):
token = auth.split(' ')[1]
username_b64, password_b64 = token.split(':')
username = base64.b64decode(username_b64).decode('utf-8')
password = base64.b64decode(password_b64).decode('utf-8')
conn = sqlite3.connect('example.db')
cur = conn.cursor()
query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"
cur.execute(query)
user = cur.fetchone()
return jsonify({'user': user})
return jsonify({'error': 'Missing credentials'}), 401
The above is vulnerable because username and password are interpolated directly into the SQL string. An attacker can supply a password like ' OR 1=1 -- to bypass authentication or extract data.
Secure remediation with parameterized queries:
import base64
from flask import request, jsonify
import sqlite3
@app.route('/profile')
def profile():
auth = request.headers.get('Authorization', '')
if auth.startswith('Basic '):
token = auth.split(' ')[1]
username_b64, password_b64 = token.split(':')
username = base64.b64decode(username_b64).decode('utf-8')
password = base64.b64decode(password_b64).decode('utf-8')
conn = sqlite3.connect('example.db')
cur = conn.cursor()
cur.execute("SELECT * FROM users WHERE username = ? AND password = ?", (username, password))
user = cur.fetchone()
return jsonify({'user': user})
return jsonify({'error': 'Missing credentials'}), 401
Using ? placeholders ensures that the username and password are treated strictly as data, preventing injection. For production, prefer an ORM such as SQLAlchemy, which further reduces risk:
from flask_sqlalchemy import SQLAlchemy
from flask import request, jsonify
import base64
db = SQLAlchemy()
@app.route('/profile')
def profile():
auth = request.headers.get('Authorization', '')
if auth.startswith('Basic '):
token = auth.split(' ')[1]
username_b64, password_b64 = token.split(':')
username = base64.b64decode(username_b64).decode('utf-8')
password = base64.b64decode(password_b64).decode('utf-8')
user = db.session.execute(
select(User).where((User.username == username) & (User.password == password))
).scalar_one_or_none()
if user:
return jsonify({'user': {'id': user.id, 'username': user.username}})
return jsonify({'error': 'Invalid credentials'}), 401
Additional remediation steps include enforcing HTTPS to protect the base64-encoded credentials in transit, hashing passwords with a strong algorithm (e.g., bcrypt) rather than storing or comparing plaintext passwords, and applying the principle of least privilege to the database user account used by the application.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |