Dictionary Attack in Flask with Bearer Tokens
Dictionary Attack in Flask with Bearer Tokens — how this specific combination creates or exposes the vulnerability
A dictionary attack in a Flask API that uses Bearer tokens attempts to gain access by systematically submitting many candidate tokens until one is accepted. Even when tokens are long and random, attackers may rely on leaked or low-entropy values (e.g., API keys stored insecurely, predictable generation, or tokens reused across services). If your Flask endpoint does not enforce strict token validation and rate controls, an attacker can iterate through a list of plausible tokens and observe whether responses change from 401/403 to 200, confirming valid credentials without ever needing to crack a cryptographic secret.
Flask APIs commonly expose token validation logic in route decorators or before_request hooks, for example checking an Authorization header directly or via an auth_required decorator. Consider this typical implementation:
from flask import Flask, request, jsonify
app = Flask(__name__)
VALID_TOKENS = {"abc123", "secret456", "token789"}
@app.before_request
def require_auth():
if request.path.startswith("/admin"):
auth = request.headers.get("Authorization")
if not auth or not auth.startswith("Bearer "):
return jsonify({"error": "missing_bearer_token"}), 401
token = auth.split(" ", 1)[1]
if token not in VALID_TOKENS:
return jsonify({"error": "invalid_token"}), 403
# request proceeds
@app.route("/admin/data")
def admin_data():
return jsonify({"data": "sensitive"})
This pattern reveals two weaknesses relevant to dictionary attacks. First, the server-side check leaks information through timing and response differences: a 403 for an unknown token versus a 200 for a valid token lets an attacker infer token validity. Second, if the token space is small or derived from low-entropy sources (e.g., short strings, predictable hashes), an attacker can build or use a dictionary of likely tokens and probe the endpoint sequentially or in parallel. In a black-box scenario, the attacker only sees whether each submission results in authorization, enabling offline enumeration of valid Bearer tokens.
Because middleBrick scans the unauthenticated attack surface, it can detect endpoints that accept Bearer tokens but lack protections such as constant-time comparison, token rate limiting, or token invalidation mechanisms. Without these controls, a dictionary attack can be constructed using common API token formats or tokens harvested from other breaches. Even if tokens are cryptographically strong, poor operational practices (e.g., logging tokens, reusing them across services, or storing them in source control) expand the dictionary, increasing risk. The scanner’s Authentication and BOLA/IDOR checks can surface endpoints where token guessing is feasible, and findings will include severity, references to real-world patterns, and remediation guidance.
Additionally, if your API specification (OpenAPI 2.0/3.0/3.1) defines securitySchemes of type http with bearerFormat, middleBrick cross-references the spec definition with runtime behavior. This helps identify mismatches where documentation claims Bearer protection exists but enforcement is incomplete. Findings align with frameworks such as OWASP API Top 10 and can map to compliance considerations around authentication and access control.
Bearer Tokens-Specific Remediation in Flask — concrete code fixes
To mitigate dictionary attacks against Bearer tokens in Flask, combine constant-time validation, strict token management, and rate controls. Avoid early returns that reveal token validity through status code differences, and ensure token comparison does not leak timing information.
Use a constant-time comparison function and centralize authorization logic to keep behavior uniform for valid and invalid tokens. Here is a hardened example:
import hmac
import os
import time
from flask import Flask, request, jsonify
app = Flask(__name__)
VALID_TOKENS = {"abc123", "secret456", "token789"}
def constant_time_token_check(a, b):
return hmac.compare_digest(a, b)
@app.before_request
def require_auth():
if request.path.startswith("/admin"):
auth = request.headers.get("Authorization")
expected_token = None
if auth and auth.startswith("Bearer "):
expected_token = auth.split(" ", 1)[1]
# Use a dummy token for comparison when missing to keep timing similar
candidate = expected_token or ""
# Compare against all valid tokens with constant time to avoid early exit
valid = False
for t in VALID_TOKENS:
if constant_time_token_check(candidate, t):
valid = True
break
if not valid:
# Always return the same status and avoid revealing why
return jsonify({"error": "unauthorized"}), 401
# request proceeds
@app.route("/admin/data")
def admin_data():
return jsonify({"data": "sensitive"})
Key improvements include using hmac.compare_digest for constant-time comparison, always performing a comparison (even when no token is provided), and returning a generic error to prevent attackers from distinguishing between missing and invalid tokens. This reduces information leakage that could aid a dictionary attack.
Complement these code changes with operational practices: generate tokens using a cryptographically secure random source, rotate tokens periodically, avoid logging full tokens, and isolate high-privilege endpoints behind additional controls. If you use the middleBrick CLI (middlebrick scan
For continuous protection, the Pro plan supports continuous monitoring so that API changes triggering new authentication patterns can be flagged automatically. The MCP Server also lets you scan APIs directly from your AI coding assistant, embedding security checks into development workflows without requiring manual configuration.