HIGH vulnerable componentsflaskbearer tokens

Vulnerable Components in Flask with Bearer Tokens

Vulnerable Components in Flask with Bearer Tokens — how this specific combination creates or exposes the vulnerability

Flask does not enforce authentication by default. When APIs use Bearer Tokens in the Authorization header, three common implementation gaps can expose endpoints: missing validation of the token format, accepting tokens over non-TLS channels, and treating bearer identity as authorization. Together, these gaps can lead to Broken Object Level Authorization (BOLA/IDOR), unsafe consumption of untrusted input, and excessive agency when token handling is coupled with dynamic routing or mass assignment.

1) Missing validation and case-sensitive token handling. If a route reads request.headers.get('Authorization') and only checks for a non-empty string, an attacker can supply any string (e.g., Bearer invalid) and still pass the check. Without verifying token format (e.g., expecting Bearer followed by a structured token), malformed or missing tokens may be accepted, effectively bypassing authentication.

2) Accepting Bearer tokens over HTTP. Transmitting tokens without TLS exposes the bearer credential to interception. Even if the token is validated, sending it in cleartext violates confidentiality and enables replay. APIs that expose unauthenticated attack surface endpoints while accepting bearer tokens over HTTP increase exposure of credentials and session tokens.

3) Treating bearer identity as authorization. A common pattern decodes a JWT from the Bearer token and uses claims such as sub to identify a user, but then uses that identifier directly in database queries without enforcing ownership checks. For example, an endpoint like /users/<user_id>/profile that trusts a decoded user_id from the token without verifying that the token’s subject matches the requested resource enables BOLA/IDOR. If the token is issued with excessive scopes or roles, and those are not validated per endpoint, it can lead to privilege escalation and unsafe consumption patterns.

These issues map to multiple checks in middleBrick’s 12 scans. Authentication checks verify whether endpoints require valid credentials and whether bearer tokens are properly validated. BOLA/IDOR tests confirm whether object-level access controls align with the authenticated identity derived from the token. Input Validation and Unsafe Consumption checks ensure that data from bearer contexts is not used to infer access to other resources or to execute unsafe operations. When combined, these gaps create a scenario where an API appears authenticated but is actually vulnerable to unauthorized access via predictable or missing authorization logic.

Example of a vulnerable Flask route that illustrates these gaps:

from flask import Flask, request, jsonify

app = Flask(__name__)

# Vulnerable: no real token validation, no HTTPS enforcement, no ownership check
@app.route('/api/users/<int:user_id>/profile')
def get_user_profile(user_id):
    auth = request.headers.get('Authorization', '')
    if not auth.startswith('Bearer '):
        return jsonify({'error': 'missing or invalid bearer token'}), 401
    token = auth.split(' ', 1)[1]
    # No verification of token signature or scope
    # No check that the requesting subject matches user_id
    return jsonify({'user_id': user_id, 'profile': 'data'})

Bearer Tokens-Specific Remediation in Flask — concrete code fixes

Remediation centers on strict token validation, transport security, and explicit authorization checks. Use a library to verify JWTs, enforce HTTPS in production, and ensure the subject of the token matches the requested resource. Below are concrete, working examples that address each of the three gaps.

1) Validate Bearer token format and presence. Require the Authorization header to start with Bearer and extract the token safely. Optionally verify the token structure before proceeding.

from flask import Flask, request, jsonify

def get_bearer_token(req):
    auth = req.headers.get('Authorization', '')
    parts = auth.split()
    if len(parts) != 2 or parts[0].lower() != 'bearer':
        return None
    return parts[1]

@app.route('/api/users/<int:user_id>/profile')
def get_user_profile(user_id):
    token = get_bearer_token(request)
    if token is None:
        return jsonify({'error': 'invalid authorization header format'}), 401
    # TODO: verify token signature and claims
    return jsonify({'user_id': user_id, 'profile': 'data'})

2) Enforce HTTPS and reject tokens over HTTP. In production, ensure requests are served over TLS and reject cleartext token transmission. This example uses a before_request hook to block non-TLS in environments where TLS termination is expected.

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.before_request
def enforce_https():
    if not request.is_secure:
        return jsonify({'error': 'HTTPS required'}), 403

def get_bearer_token(req):
    auth = req.headers.get('Authorization', '')
    parts = auth.split()
    if len(parts) != 2 or parts[0].lower() != 'bearer':
        return None
    return parts[1]

@app.route('/api/users/<int:user_id>/profile')
def get_user_profile(user_id):
    token = get_bearer_token(request)
    if token is None:
        return jsonify({'error': 'invalid authorization header format'}), 401
    # TODO: verify token signature and claims
    return jsonify({'user_id': user_id, 'profile': 'data'})

3) Map token identity to resource ownership. Decode the JWT (using a verified library), extract the subject, and compare it with the requested user_id. This prevents BOLA/IDOR by ensuring the token’s subject matches the resource being accessed.

import jwt
from flask import Flask, request, jsonify

app = Flask(__name__)
SECRET_KEY = 'your-very-secret-key'
ALGORITHM = 'HS256'

def get_bearer_token(req):
    auth = req.headers.get('Authorization', '')
    parts = auth.split()
    if len(parts) != 2 or parts[0].lower() != 'bearer':
        return None
    return parts[1]

def decode_token(token):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except jwt.InvalidTokenError:
        return None

@app.route('/api/users/<int:user_id>/profile')
def get_user_profile(user_id):
    token = get_bearer_token(request)
    if token is None:
        return jsonify({'error': 'invalid authorization header format'}), 401
    payload = decode_token(token)
    if payload is None:
        return jsonify({'error': 'invalid token'}), 401
    subject = payload.get('sub')
    if subject is None or str(subject) != str(user_id):
        return jsonify({'error': 'forbidden: token subject does not match resource'}), 403
    return jsonify({'user_id': user_id, 'profile': 'data'})

Additional recommendations: rotate signing keys, set short token lifetimes, and scope tokens with claims that are validated per endpoint. For broader coverage, middleBrick’s scans can validate authentication mechanisms and flag endpoints where Bearer handling does not align with expected identity and authorization checks.

Frequently Asked Questions

Why does accepting Bearer tokens over HTTP increase risk even if tokens are validated?
Transmitting tokens over HTTP exposes bearer credentials to interception, enabling replay and token theft. Validation alone does not protect confidentiality in transit; TLS is required to prevent on-path attackers from capturing the token.
How can middleBrick help identify Bearer token misconfigurations?
middleBrick runs authentication and BOLA/IDOR checks that test whether endpoints properly validate bearer tokens and enforce ownership. It also flags endpoints accepting tokens over non-TLS channels as part of its unauthenticated attack surface testing.