Pii Leakage in Flask with Bearer Tokens
Pii Leakage in Flask with Bearer Tokens — how this specific combination creates or exposes the vulnerability
In Flask APIs that use Bearer Tokens for authentication, PII leakage commonly arises when endpoints authenticate requests but then return sensitive user data without adequate authorization checks or output safeguards. A typical pattern is reading the token from the Authorization header, validating it (for example against a database or cache), and proceeding to expose user profile or account information. If route logic omits proper access controls, an attacker who obtains or guesses a valid token can view PII belonging to other users by manipulating identifiers or exploiting weak ownership checks. This risk is compounded when responses include fields such as email, phone, government ID, or internal user IDs that should be restricted to the authenticated subject only.
Even when tokens are validated, leakage can occur through misconfigured serialization, verbose error messages, or improper logging that exposes tokens or associated PII in server logs or error responses. Flask’s default JSON encoder may inadvertently serialize sensitive fields if the response model is not carefully defined. For instance, an endpoint like /users/<user_id> that uses a token to identify the requester might fail to ensure that the requested user_id matches the token’s subject, allowing horizontal privilege escalation and broad PII exposure. Compounded with missing rate limiting or weak audit trails, an attacker can probe multiple user IDs to harvest large datasets of PII without triggering defenses.
The LLM/AI Security checks unique to middleBrick specifically look for system prompt leakage and output exposure risks. When an LLM endpoint is integrated into a Flask service, responses that include PII, API keys, or executable code are flagged. For example, if a Flask route returns model-generated text that contains user email addresses or tokens in clear text, middleBrick’s output scanning detects these patterns and highlights them as high-severity findings. This is especially relevant when token handling and data exposure checks intersect: a Bearer token may be logged or echoed inadvertently, creating a chain that exposes both authentication material and personal data.
Using OpenAPI/Swagger spec analysis, middleBrick cross-references definitions and runtime behavior to identify mismatches where endpoints claim to require authentication but do not enforce scope- or subject-based restrictions. This helps uncover cases where Bearer token validation is present but authorization logic is incomplete, enabling attackers to leverage a single token to traverse multiple user contexts and extract PII. The scanner also checks for insecure integrations, such as endpoints that accept tokens but lack proper input validation or encryption, increasing the likelihood of token theft or session fixation that further amplifies PII leakage risk.
Bearer Tokens-Specific Remediation in Flask — concrete code fixes
To mitigate PII leakage when using Bearer Tokens in Flask, enforce strict ownership checks, minimize data exposure in responses, and ensure tokens and PII are never logged or echoed. Below are concrete code examples illustrating secure patterns.
1. Validate token and enforce subject ownership:
from flask import Flask, request, jsonify, g
import jwt
app = Flask(__name__)
SECRET_KEY = 'your_jwt_secret_key'
def get_token_auth():
auth = request.headers.get('Authorization')
if not auth or not auth.startswith('Bearer '):
return None
token = auth.split(' ')[1]
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
return payload
except jwt.ExpiredSignatureError:
return None
except jwt.InvalidTokenError:
return None
@app.before_request
def authenticate():
token_payload = get_token_auth()
if not token_payload:
return jsonify({'error': 'unauthorized'}), 401
g.user = token_payload # contains 'sub' and possibly 'scope'
@app.route('/users/me')
def get_current_user():
# Only return data for the token subject
user_id = g.user.get('sub')
user_data = fetch_user_data_safe(user_id)
return jsonify(user_data)
def fetch_user_data_safe(user_id):
# Example: fetch only allowed fields from DB
user = db_get_user_by_id(user_id)
if not user:
return {'error': 'not found'}, 404
# Explicitly limit exposure
return {
'id': user.id,
'email': user.email,
'name': user.name
# Do not include sensitive fields like ssn or internal_role
}
2. Avoid logging tokens or PII and sanitize responses:
import logging
from flask import Flask, request, jsonify
app = Flask(__name__)
logger = logging.getLogger('api')
@app.after_request
def remove_sensitive_headers(response):
# Ensure tokens and PII are not echoed in headers or body
response.headers.pop('Authorization', None)
return response
@app.errorhandler(Exception)
def handle_error(e):
# Do not include request details that may contain tokens or PII
logger.warning('Request failed: %s', request.path)
return jsonify({'error': 'internal server error'}), 500
3. Use scopes and fine-grained authorization:
def requires_scope(required_scope):
def decorator(f):
def wrapper(*args, **kwargs):
token_payload = g.user
scopes = token_payload.get('scope', '').split()
if required_scope not in scopes:
return jsonify({'error': 'insufficient scope'}), 403
return f(*args, **kwargs)
return wrapper
return decorator
@app.route('/users/me/settings')
@requires_scope('settings:read')
def get_settings():
user_id = g.user.get('sub')
settings = db_get_settings_for_user(user_id)
return jsonify(settings)
4. Secure token handling in client code (curl example):
# Request with Bearer token
curl -s -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." https://api.example.com/users/me
These practices reduce the surface for PII leakage by ensuring tokens are validated, subject boundaries are enforced, and sensitive data is never unnecessarily exposed or logged. middleBrick’s scans can verify that such controls are present by analyzing your OpenAPI spec and runtime behavior, highlighting missing ownership checks and overly permissive responses.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |