Auth Bypass in Flask with Bearer Tokens
Auth Bypass in Flask with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Flask APIs that rely on Bearer tokens for authentication can permit an Auth Bypass when token validation is inconsistently enforced across endpoints or when token extraction is fragile. The vulnerability occurs when a route either skips the token-verification function, incorrectly trusts request attributes, or fails to secure the token issuance endpoint itself.
Consider a Flask app that defines a require_token decorator but applies it selectively. If an administrative route is accidentally omitted, an unauthenticated attacker can reach privileged functionality even though most endpoints require a Bearer token. Incomplete decorator coverage is a common implementation error.
from flask import Flask, request, jsonify
def require_token(f):
def wrapper(*args, **kwargs):
auth = request.headers.get('Authorization')
if not auth or not auth.startswith('Bearer '):
return jsonify({'error': 'missing or invalid token'}), 401
token = auth.split(' ')[1]
if token != 's3cr3t_v4lid_t0k3n':
return jsonify({'error': 'invalid token'}), 401
return f(*args, **kwargs)
wrapper.__name__ = f.__name__
return wrapper
app = Flask(__name__)
@app.route('/public')
def public():
return jsonify({'msg': 'public endpoint'})
@app.route('/admin')
@require_token
def admin():
return jsonify({'msg': 'admin endpoint'})
if __name__ == '__main__':
app.run()
In the example, the /admin route is protected, but if a developer later adds a new privileged route and forgets to add @require_token, the Auth Bypass exists. Additionally, if the token validation logic resides in middleware that does not run for all paths (for example, due to route ordering or blueprint configuration), some routes may be processed without verification.
Another realistic issue stems from how the token is compared. A naive string comparison can be vulnerable to certain timing-related side channels or misconfiguration. More importantly, if the token is expected in a specific format (e.g., a JWT) but the app only checks a static string, an attacker does not need to crack or steal a real token; they only need to know the exact string the server checks, which can be discovered through source code review or misconfigured logging.
Flask apps that parse the Authorization header inconsistently also risk bypass. For example, if a proxy or load balancer terminates TLS and forwards requests as HTTP, the header may be transformed or stripped. If the app falls back to alternative sources (e.g., a custom header) without strict validation, an attacker can supply a spoofed header that bypasses the Bearer check.
Auth Bypass in this context is not always a missing decorator. It can be a logic flaw where the token is accepted from an unexpected location, or where the validation result is not enforced uniformly. Because middleBrick scans test the unauthenticated attack surface, it can flag routes that lack required authentication checks and highlight inconsistencies in how Bearer tokens are enforced across the API surface.
Bearer Tokens-Specific Remediation in Flask — concrete code fixes
Remediation centers on consistent, centralized token validation and strict handling of the Authorization header. Implement a single, reusable decorator that every protected route uses, and ensure the decorator is applied before any route logic executes.
Use constant-time comparisons for token validation to reduce timing side-channel risks, and prefer structured tokens such as JWTs with proper signature verification over static strings. Below is a hardened example using PyJWT for token verification and a centralized decorator.
import jwt
from flask import Flask, request, jsonify
from functools import wraps
from datetime import datetime, timezone
app = Flask(__name__)
SECRET_KEY = 'your_strong_secret_here'
ALGORITHM = 'HS256'
def require_token(f):
@wraps(f)
def wrapper(*args, **kwargs):
auth = request.headers.get('Authorization')
if not auth:
return jsonify({'error': 'authorization header missing'}), 401
parts = auth.split()
if len(parts) != 2 or parts[0].lower() != 'bearer':
return jsonify({'error': 'invalid authorization format, expected Bearer token'}), 401
token = parts[1]
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
# optionally enforce exp, iss, or scope checks here
request.token_payload = payload
except jwt.ExpiredSignatureError:
return jsonify({'error': 'token expired'}), 401
except jwt.InvalidTokenError:
return jsonify({'error': 'invalid token'}), 401
return f(*args, **kwargs)
return wrapper
@app.route('/public')
def public():
return jsonify({'msg': 'public endpoint'})
@app.route('/admin')
@require_token
def admin():
return jsonify({'msg': 'admin endpoint', 'user': request.token_payload.get('sub')})
if __name__ == '__main__':
app.run()
Key remediation practices:
- Apply the
@require_tokendecorator to every route that requires authentication; avoid omissions by reviewing all routes during code reviews. - Validate the Authorization header format strictly: it must contain exactly two parts, with the first part being
Bearer(case-insensitive). - Use a library such as PyJWT to decode and verify signed tokens. Verify the signature, and where relevant check claims like
exp(expiration) andiss(issuer). - Avoid static string comparisons for production tokens; use cryptographic verification so that token compromise on one client does not trivially compromise the API.
- If your architecture uses a proxy, ensure the Authorization header is preserved end-to-end and not stripped or rewritten in a way that bypasses validation.
These changes ensure that authentication is enforced consistently, reducing the likelihood of an Auth Bypass. middleBrick’s unauthenticated scans can verify whether protected routes still lack proper token checks and whether token validation logic is reachable without credentials.
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 |