Timing Attack in Flask
How Timing Attack Manifests in Flask
In a Flask application, timing attacks often appear when secret values (API keys, tokens, password hashes) are compared using non‑constant‑time operations such as the == operator or string .equals() methods. Because Python’s string comparison short‑circuits on the first mismatched character, an attacker can measure response times to guess each character of the secret.
A typical vulnerable pattern looks like this:
from flask import Flask, request, abort
app = Flask(__name__)
API_KEY = "s3cr3t_k3y_123" # hard‑coded for illustration
@app.route("/data")
def get_data():
provided = request.headers.get("X-API-Key")
if provided == API_KEY: # ← non‑constant‑time comparison
return {"secret": "top‑secret"}
abort(403)
if __name__ == "__main__":
app.run()
An attacker sends a series of requests with varying prefixes of the API key and records the latency. Longer response times indicate a correct prefix, allowing the key to be reconstructed character by character. Similar issues arise in:
- Custom token validation that uses
==on JWT signatures. - Password verification that compares raw hashes instead of using
werkzeug.security.check_password_hash(which internally uses constant‑time comparison). - Flask‑Login’s
user.is_authenticatedchecks that inadvertently leak timing via database lookups.
These code paths are part of the unauthenticated attack surface that middleBrick probes during its 5‑15 second black‑box scan.
Flask-Specific Detection
middleBrick detects timing vulnerabilities by sending a large number of requests with carefully crafted input variations and measuring the response time distribution. Because the scanner works without agents or credentials, it treats the endpoint as a black box and looks for statistically significant timing differences that correlate with guessed characters of a secret.
When scanning a Flask API, you can use any of the middleBrick interfaces:
- CLI:
middlebrick scan https://api.example.comreturns a JSON report that includes a finding under the "Authentication" category if a timing leak is detected. - GitHub Action: Add
uses: middlebrick/action@v1to your workflow; the action will fail the build if the security score drops below your threshold, catching regressions introduced by a new route that uses unsafe comparison. - MCP Server: From an AI coding assistant (Claude, Cursor, etc.), invoke the MCP server to scan the local Flask dev server directly from the IDE, getting immediate feedback before you push code.
- Dashboard: After a scan, the dashboard shows a per‑category breakdown; the "Authentication" card will display a timing‑attack finding with severity, remediation guidance, and a trend line over time.
The finding includes the exact endpoint tested, the observed timing delta (e.g., "+12 ms per correct character"), and a proof‑of‑concept request pattern that demonstrated the leak.
Flask-Specific Remediation
Fixing timing attacks in Flask requires replacing any non‑constant‑time secret comparison with a constant‑time alternative. Python’s standard library provides hmac.compare_digest (or secrets.compare_digest in Python 3.3+), which runs in time independent of the input values.
Here is the corrected version of the vulnerable route:
from flask import Flask, request, abort
import hmac
import hashlib
app = Flask(__name__)
API_KEY = b"s3cr3t_k3y_123" # keep as bytes for compare_digest
@app.route("/data")
def get_data():
provided = request.headers.get("X-API-Key")
if not provided:
abort(401)
# Constant‑time comparison
if not hmac.compare_digest(provided.encode(), API_KEY):
abort(403)
return {"secret": "top‑secret"}
if __name__ == "__main__":
app.run()
If you are validating JWTs or other tokens, use a library that already employs constant‑time comparison (e.g., PyJWT with jwt.decode and a verified secret). For password verification, rely on werkzeug.security.check_password_hash which internally uses secrets.compare_digest.
Additional Flask‑specific hardening steps:
- Use Flask’s
@app.before_request to enforce a minimum response time (e.g.,time.sleep(0.005)) only as a defensive measure, not as a primary fix. - Enable Flask’s
SECRET_KEYwith sufficient entropy and never hard‑code it; load from environment variables or a secrets manager. - Regularly run middleBrick scans (via CLI, GitHub Action, or MCP Server) to ensure new routes do not reintroduce unsafe comparisons.
By adopting constant‑time comparison and leveraging middleBrick’s automated detection, you eliminate the timing side‑channel that attackers could otherwise exploit to steal secrets from your Flask API.
Frequently Asked Questions
Can middleBrick detect timing attacks in a Flask app that is behind a reverse proxy or load balancer?
Is it safe to rely on a fixed delay (e.g., time.sleep) to mitigate timing attacks in Flask?
hmac.compare_digest.