Information Disclosure in Flask with Bearer Tokens
Information Disclosure in Flask with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Information disclosure occurs when a Flask API unintentionally exposes sensitive data, such as authentication tokens, user details, or internal errors. In the context of Bearer Tokens, this risk typically arises from insecure token handling, verbose error messages, or misconfigured endpoints that reveal whether a token is valid or expose token metadata.
Flask itself does not enforce token validation; it relies on developer implementation. If token validation logic is incomplete—for example, checking token presence but not its signature or scope—an attacker can learn which endpoints are protected and which are not. A common pattern is to use a decorator like @token_required but fail to consistently apply it across routes, leading to inconsistent authorization boundaries.
When debugging is enabled in Flask (e.g., app.debug = True), stack traces may reveal paths, configuration values, or internal function names. If a token is sent in an Authorization header and the server responds differently based on token validity (e.g., 401 vs 404), this behavioral difference becomes an oracle for attackers to probe valid tokens—this is a form of BOLA/IDOR at the authentication boundary.
Additionally, if token introspection or revocation logic leaks information through logs, error responses, or HTTP headers (e.g., returning a 200 with an empty body for an invalid token vs 403 for an expired one), attackers can infer token state. Insecure default configurations, such as allowing the flask development server in production or not setting PROPAGATE_EXCEPTIONS carefully, can amplify disclosure through unhandled exceptions.
Another vector is through OpenAPI or Swagger documentation served in development. If spec files expose example tokens or include comments describing internal token formats, this documentation itself becomes a data exposure channel. middleBrick scans detect these risks by correlating spec definitions with runtime behavior, identifying inconsistencies such as missing authentication on sensitive routes.
Concrete example of a vulnerable route in Flask:
from flask import Flask, request, jsonify
app = Flask(__name__)
# Insecure: no consistent token validation
@app.route('/public')
def public():
return jsonify({"message": "public data"})
@app.route('/admin')
def admin():
token = request.headers.get('Authorization', '').replace('Bearer ', '')
if not token:
return jsonify({"error": "missing token"}), 401
# Weak validation: only checks presence, not correctness
if token == 'secret123':
return jsonify({"data": "admin panel"})
return jsonify({"error": "invalid token"}), 403
if __name__ == '__main__':
app.run(debug=True)
In this example, the server reveals whether a token was missing, malformed, or incorrect through distinct HTTP status codes and messages. An attacker can iterate over likely tokens or use automated probes to map protected vs unprotected endpoints, leading to information disclosure. middleBrick’s 12 checks run in parallel to detect such authorization inconsistencies and specification drift without requiring credentials.
Bearer Tokens-Specific Remediation in Flask — concrete code fixes
Remediation centers on consistent token validation, avoiding information leaks, and ensuring secure defaults. Use a dedicated library such as authlib or validate tokens against a known issuer and signature rather than simple string comparison.
First, standardize responses for authentication failures to return the same status code and minimal message regardless of failure reason. Use 401 for missing or malformed tokens and avoid exposing token validity details.
Second, validate tokens before route execution using a reusable function or decorator, and apply it uniformly across all protected endpoints. Never rely on manual checks inside each route.
Third, disable debug mode in production and ensure exceptions are not propagated in a way that reveals internal state.
Secure Flask example with Bearer Token validation:
from flask import Flask, request, jsonify
import jwt
from functools import wraps
app = Flask(__name__)
app.config['PROPAGATE_EXCEPTIONS'] = False
SECRET_KEY = 'your-secure-secret'
ALGORITHM = 'HS256'
def token_required(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.headers.get('Authorization')
if not auth or not auth.startswith('Bearer '):
return jsonify({"error": "unauthorized"}), 401
token = auth.split(' ')[1]
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
request.user = payload
except jwt.ExpiredSignatureError:
return jsonify({"error": "token expired"}), 401
except jwt.InvalidTokenError:
return jsonify({"error": "invalid token"}), 401
return f(*args, **kwargs)
return decorated
@app.route('/public')
def public():
return jsonify({"message": "public data"})
@app.route('/admin')
@token_required
def admin():
return jsonify({"data": "admin panel for user: " + str(request.user)})
if __name__ == '__main__':
# In production, use a proper WSGI server and set debug=False
app.run(debug=False)
This approach ensures consistent error handling, avoids leaking token validity details, and validates tokens cryptographically. For production, store secrets securely (e.g., environment variables), use HTTPS, and rotate keys regularly.
When using an API spec, ensure that securitySchemes are defined for Bearer tokens and that every path requiring authentication is explicitly marked. middleBrick’s OpenAPI/Swagger analysis resolves $ref definitions and cross-references them with runtime checks to identify missing authentication on routes.
Additional remediation steps include:
- Avoid returning detailed errors in production; use generic messages.
- Set secure HTTP headers (e.g.,
X-Content-Type-Options: nosniff). - Rate-limit authentication endpoints to mitigate brute-force probing.
middleBrick’s Pro plan enables continuous monitoring so that any future changes to token handling or route permissions are flagged promptly, and the GitHub Action can enforce a minimum score threshold before deployment.