Auth Bypass in Flask
How Auth Bypass Manifests in Flask
Auth bypass in Flask applications typically occurs through several Flask-specific patterns that developers often overlook. The most common scenario involves route protection that appears to work but has subtle flaws in its implementation.
Consider a typical Flask application using a decorator-based authentication system:
from flask import Flask, request, session, redirect, url_for
from functools import wraps
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not session.get('logged_in'):
return redirect(url_for('login'))
return f(*args, **kwargs)
return decorated_function
@app.route('/admin')
@login_required
def admin_panel():
return 'Admin Dashboard'
This pattern seems secure, but auth bypass can occur through several Flask-specific mechanisms:
Method-Specific Bypass: If the decorator only checks GET requests but the endpoint accepts POST, PUT, or DELETE methods, attackers can bypass authentication by using different HTTP methods:
@app.route('/admin', methods=['GET', 'POST'])
@login_required
def admin_panel():
if request.method == 'POST':
# This POST handler runs even if GET is protected
return process_admin_action()
return 'Admin Dashboard'
Blueprint Route Registration: Flask blueprints can create auth bypass vulnerabilities when routes are registered with different prefixes or when blueprint-level decorators don't apply to all routes:
bp = Blueprint('admin', __name__)
@bp.route('/dashboard')
@login_required
def dashboard():
return 'Dashboard'
# This route might be registered without the blueprint prefix
app.add_url_rule('/admin/secret', 'secret_route', secret_function)
Session Fixation and Flask's Secure Cookie: Flask's default session implementation uses client-side signed cookies. If the secret key is weak or exposed, attackers can manipulate session data:
# Vulnerable: predictable secret key
app.secret_key = 'supersecretkey'
# Attacker can forge sessions:
session['logged_in'] = True
session['user_id'] = 1 # Admin user
CORS Misconfiguration: Flask-CORS or manual CORS headers can inadvertently allow unauthorized cross-origin requests to protected endpoints:
from flask_cors import CORS
# Too permissive - allows any origin
CORS(app, origins='*')
# This protected endpoint can now be accessed from any domain
@app.route('/api/private')
@login_required
def private_data():
return jsonify(sensitive_data)
Flask-Specific Detection
Detecting auth bypass in Flask applications requires examining both the application code and runtime behavior. Here are Flask-specific detection methods:
Code Analysis: Look for common Flask auth bypass patterns in your codebase:
# Check for missing decorators on routes
from flask import Flask
app = Flask(__name__)
# Find all routes and check for authentication decorators
for rule in app.url_map.iter_rules():
endpoint = app.view_functions.get(rule.endpoint)
# Check if @login_required or similar decorator is present
# This requires inspecting function decorators or using static analysis
middleBrick API Security Scanner: middleBrick specifically tests Flask applications for auth bypass vulnerabilities by:
- Testing all HTTP methods on protected endpoints (GET, POST, PUT, DELETE, PATCH)
- Checking for session fixation vulnerabilities by manipulating session cookies
- Testing CORS misconfigurations by making cross-origin requests
- Verifying that authentication decorators apply to all route methods
- Checking for blueprint registration issues where routes might be exposed without protection
Runtime Testing: Use Flask's test client to simulate bypass attempts:
import unittest
from your_app import app
class AuthBypassTests(unittest.TestCase):
def setUp(self):
self.client = app.test_client()
def test_auth_bypass_methods(self):
# Test if POST/PUT/DELETE bypass GET protection
response = self.client.post('/admin', data={'action': 'delete'})
self.assertNotEqual(response.status_code, 200)
def test_session_manipulation(self):
# Test if session can be forged
with self.client.session_transaction() as session:
session['logged_in'] = True
session['user_id'] = 1
response = self.client.get('/admin')
# Should redirect if session manipulation is prevented
self.assertEqual(response.status_code, 302)
middleBrick CLI Integration: Scan your Flask API directly from terminal:
# Install middleBrick CLI
npm install -g middlebrick
# Scan your Flask API
middlebrick scan http://localhost:5000
# Or integrate into your Flask app's test suite
middlebrick scan --json http://localhost:5000/api/v1
Flask-Specific Remediation
Securing Flask applications against auth bypass requires both code fixes and configuration changes. Here are Flask-specific remediation strategies:
Robust Authentication Decorator: Create a comprehensive decorator that checks all HTTP methods and validates session integrity:
from functools import wraps
from flask import request, session, redirect, url_for, jsonify
def secure_login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
# Check all HTTP methods
if request.method not in ['GET', 'POST', 'PUT', 'DELETE', 'PATCH']:
return jsonify({'error': 'Method not allowed'}), 405
# Verify session exists and is valid
if 'logged_in' not in session or not session['logged_in']:
return redirect(url_for('login', next=request.url))
# Additional session validation
if not validate_session(session):
session.clear()
return redirect(url_for('login'))
return f(*args, **kwargs)
return decorated_function
# Apply to all routes
@app.route('/admin', methods=['GET', 'POST', 'PUT', 'DELETE'])
@secure_login_required
def admin_panel():
if request.method == 'POST':
return process_admin_action()
return 'Admin Dashboard'
Session Security: Use Flask's session security features and add additional validation:
from flask import Flask, session
from itsdangerous import URLSafeTimedSerializer
app = Flask(__name__)
app.secret_key = os.environ.get('FLASK_SECRET_KEY', 'fallback-secret')
# Use a strong secret key from environment
# Implement session timeout and validation
@app.before_request
def check_session_timeout():
if 'last_activity' in session:
now = datetime.utcnow()
if (now - session['last_activity']).total_seconds() > 3600: # 1 hour timeout
session.clear()
session['last_activity'] = datetime.utcnow()
# Validate session data integrity
def validate_session(session_data):
try:
# Check for expected session structure
if not isinstance(session_data.get('user_id'), int):
return False
if not isinstance(session_data.get('logged_in'), bool):
return False
return True
except:
return False
CORS Configuration: Properly configure CORS to prevent unauthorized cross-origin access:
from flask_cors import CORS
# Only allow specific origins
CORS(app, origins=['https://yourdomain.com'], supports_credentials=True)
# Or use a CORS decorator for fine-grained control
@app.route('/api/private')
@cross_origin(origins=['https://yourdomain.com'], supports_credentials=True)
@login_required
def private_data():
return jsonify(sensitive_data)
Blueprint Security: Ensure consistent authentication across blueprints:
bp = Blueprint('admin', __name__, url_prefix='/admin')
# Apply decorator at blueprint level
@bp.record_once
def register_hook(state):
def apply_decorator_to_all_views():
for view_func in bp.view_functions.values():
if not hasattr(view_func, 'auth_checked'):
setattr(view_func, 'auth_checked', True)
# Apply your auth decorator here
state.app.context_processor(apply_decorator_to_all_views)
middleBrick Integration: Use middleBrick to verify your fixes:
# Scan after implementing fixes
middlebrick scan http://localhost:5000 --category auth
# Check the report for any remaining auth bypass vulnerabilities
# middleBrick will test all HTTP methods, session manipulation, and CORS
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |