Token Leakage in Flask with Hmac Signatures
Token Leakage in Flask with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Token leakage occurs when authentication tokens are exposed in logs, URLs, or error messages. In Flask applications that use HMAC signatures for request authentication, leakage often arises from inconsistent handling of the signature and token material. HMAC signatures are typically computed over a canonical representation of the request—such as selected headers, method, and body—then transmitted in a header like X-Signature. If the application also passes the token in a query parameter or within the JSON payload and later logs the full request, the token can be stored in plaintext alongside the signature data.
Consider a Flask route that expects an HMAC signature in a header and a bearer token in the query string. If the developer logs request.url or the full request.args for debugging, the token becomes part of the log entry. Because the signature does not inherently hide or protect the token, anyone with access to logs can harvest valid tokens. This is especially risky when tokens are long-lived or have broad scopes. The signature provides integrity and authenticity for the request but does not prevent leakage if the token itself is exposed in logs, browser history, or referrer headers.
Another common pattern is using HMAC to sign a payload that includes the token, then returning the token in a redirect or client-side storage. If the server response inadvertently echoes the token—such as embedding it in a JSON response for client-side use—an attacker who can intercept or read the response can capture the token. Even when the signature validates correctly, the token remains vulnerable if it travels in clear text through channels that are not end-to-end encrypted or are exposed via insecure storage practices.
Middleware or instrumentation that captures request and response bodies for monitoring can also contribute to leakage. In Flask, extensions that log payloads for observability might record the token if it is present in the request body, regardless of the HMAC verification outcome. Because HMAC verification happens after the request data is parsed, tokens can be logged before the application decides whether the signature is valid, increasing the window of exposure.
Real-world examples include API clients that include an api_token query parameter while also providing an HMAC signature header derived from selected headers and the POST body. If the server logs incoming requests for troubleshooting, the token is stored in logs in clear association with the signature. Similarly, returning the token in error messages—such as Invalid token for payload signature—can reveal valid tokens to attackers who trigger controlled errors. These patterns illustrate why token handling must be designed with the same care as the signature scheme.
Hmac Signatures-Specific Remediation in Flask — concrete code fixes
To reduce token leakage risk while using HMAC signatures in Flask, design the flow so the token is never present in logs, URLs, or response bodies. Keep the token in the request body (for POST/PUT) or in an Authorization header, and ensure your logging excludes sensitive fields. Below are concrete, realistic code examples that demonstrate a secure approach.
Example 1: HMAC verification with token in the request body (JSON)
import hashlib
import hmac
import json
from flask import Flask, request, jsonify, abort
app = Flask(__name__)
SECRET_KEY = b'super-secret-key'
def compute_signature(payload_bytes, secret):
return hmac.new(secret, payload_bytes, hashlib.sha256).hexdigest()
@app.route('/api/action', methods=['POST'])
def api_action():
# Read raw body for signature calculation
raw_body = request.get_data(as_text=False)
signature_header = request.headers.get('X-Signature')
if not signature_header:
abort(400, description='Missing signature')
# Compute expected signature over raw body
expected = compute_signature(raw_body, SECRET_KEY)
if not hmac.compare_digest(expected, signature_header):
abort(401, description='Invalid signature')
# Parse body after verification
data = json.loads(raw_body)
# Assume token is inside the JSON payload and used server-side
token = data.get('token')
if not token:
abort(400, description='Missing token')
# Do not log raw_body or token; log only non-sensitive metadata
app.logger.info('Request processed', extra={'endpoint': '/api/action'})
return jsonify({'status': 'ok'})
Example 2: HMAC with token in Authorization header (Bearer) and selected headers
from flask import Flask, request, jsonify, abort
import hashlib
import hmac
app = Flask(__name__)
SECRET_KEY = b'secret'
def compute_signature(headers, body_bytes, secret):
# Canonical string: selected headers + body hex digest for stability
canonical = '\n'.join([headers.get('X-Request-ID', ''), headers.get('Content-Type', '')])
return hmac.new(secret, canonical.encode() + body_bytes, hashlib.sha256).hexdigest()
@app.route('/api/submit', methods=['POST'])
def submit():
auth = request.headers.get('Authorization')
if not auth or not auth.startswith('Bearer '):
abort(401, description='Missing bearer token')
token = auth.split(' ', 1)[1]
# Do not include token in signature inputs; keep it separate
raw_body = request.get_data(as_text=False)
signature = request.headers.get('X-Signature')
if not signature:
abort(400, description='Missing signature')
expected = compute_signature(request.headers, raw_body, SECRET_KEY)
if not hmac.compare_digest(expected, signature):
abort(401, description='Invalid signature')
# Use token for server-side authorization without echoing it in responses
# e.g., map token to user and check scopes
return jsonify({'result': 'success'})
Operational and logging guidance
- Never log raw request URLs that may contain query parameters with tokens.
- Scrub sensitive fields from structured logs; avoid printing
request.argsorrequest.urlwhen tokens are present. - Keep tokens out of query strings; prefer headers or the request body.
- Use
hmac.compare_digestto prevent timing attacks during signature verification. - Ensure HTTPS is enforced in production to protect tokens in transit; HMAC does not replace transport encryption.
These patterns align with common API security checks such as those in the OWASP API Top 10 and can be integrated into your quality gates. With plans like the middleBrick Pro plan, you can add continuous monitoring and CI/CD integration to detect risky logging patterns and configuration issues before deployment. For automated verification in development, the middleBrick CLI allows you to scan from terminal with middlebrick scan <url>, while the GitHub Action can add API security checks to your CI/CD pipeline and fail builds if risk scores drop below your chosen threshold.