Dns Cache Poisoning in Flask with Bearer Tokens
Dns Cache Poisoning in Flask with Bearer Tokens — how this specific combination creates or exposes the vulnerability
DNS cache poisoning (also known as DNS spoofing) occurs when an attacker injects a malicious DNS record into a resolver’s cache, causing domain lookups to return attacker-controlled IP addresses. In a Flask application that relies on external service discovery or configuration endpoints, poisoned DNS responses can redirect traffic to a malicious host. If the application then uses Bearer Tokens for authentication, those tokens can be inadvertently sent to the malicious endpoint, leading to token theft or unauthorized API access.
The combination is particularly risky because Flask often integrates with third-party APIs and microservices. When Flask code resolves a hostname at runtime—such as through requests.get() or an HTTP client used to call an authorization server—a poisoned DNS entry can point to an attacker’s server. If the request includes a Bearer Token in the Authorization header, the token is transmitted to the attacker. Even if the token is not directly leaked, an attacker might intercept or manipulate the request path, leading to token replay or privilege escalation. This risk is amplified when Flask applications run in containerized or cloud environments where service discovery and dynamic DNS are common.
Consider a Flask app that retrieves an OAuth2 introspection endpoint via a hostname that could be subject to DNS manipulation:
import requests
OAUTH_INTROSPECTION_URL = 'https://auth.example.com/introspect'
BEARER_TOKEN = 'secret-token-123'
def introspect_token(token):
headers = {'Authorization': f'Bearer {token}'}
response = requests.get(OAUTH_INTROSPECTION_URL, headers=headers)
return response.json()
If an attacker poisons the DNS for auth.example.com to point to a malicious server, the Flask app will send the Bearer Token to the attacker. Because the token is embedded in the Authorization header, it becomes directly exposed. This scenario highlights the importance of validating not only the application’s logic but also the integrity of network resolution paths, especially when handling credentials.
Moreover, Flask applications that use service clients initialized with hostnames (rather than IP addresses) are susceptible to runtime DNS lookups. If those clients are configured to include Bearer Tokens in every request—such as API gateways or microservice clients—a single poisoned DNS entry can compromise multiple services. The risk is not limited to outbound calls; internal service meshes that rely on DNS-based routing can also be affected, making token leakage a cross-cutting concern.
While middleBrick does not fix runtime configuration issues, it can detect insecure patterns in API specifications and runtime behavior, such as unauthenticated endpoints or missing input validation, that may coexist with DNS-related risks. Using the CLI (middlebrick scan <url>) or integrating the GitHub Action into CI/CD pipelines can help identify related misconfigurations before deployment.
Bearer Tokens-Specific Remediation in Flask — concrete code fixes
Remediation focuses on minimizing exposure of Bearer Tokens and ensuring that DNS resolution and HTTP requests are as resilient as possible. Below are concrete, secure coding patterns for Flask applications.
1. Avoid embedding tokens in code or configuration
Never hardcode Bearer Tokens in source code or configuration files. Instead, use environment variables or a secure secrets manager. This reduces the risk of token leakage through version control or logs.
import os
from flask import Flask, request
import requests
app = Flask(__name__)
# Load token from environment at runtime
BEARER_TOKEN = os.getenv('OAUTH_INTROSPECTION_TOKEN')
if not BEARER_TOKEN:
raise RuntimeError('Missing OAUTH_INTROSPECTION_TOKEN environment variable')
OAUTH_INTROSPECTION_HOST = os.getenv('OAUTH_INTROSPECTION_HOST', 'auth.example.com')
def introspect_token(token):
url = f'https://{OAUTH_INTROSPECTION_HOST}/introspect'
headers = {'Authorization': f'Bearer {token}'}
response = requests.get(url, headers=headers, timeout=5)
response.raise_for_status()
return response.json()
2. Use IP addresses or certificate pinning where feasible
For critical endpoints, prefer IP addresses or implement certificate pinning to reduce reliance on DNS. While not always practical, this limits the attack surface to DNS manipulation.
import requests
# Example using a pinned IP and host header
OAUTH_INTROSPECTION_URL = 'https://192.0.2.1/introspect'
def introspect_token_with_pinning(token):
headers = {
'Authorization': f'Bearer {token}',
'Host': 'auth.example.com' # Ensure correct host header
}
response = requests.get(OAUTH_INTROSPECTION_URL, headers=headers, verify=True, timeout=5)
return response.json()
3. Validate and sanitize external configuration
If your application dynamically constructs endpoints, validate hostnames against an allowlist and reject unexpected domains.
ALLOWED_HOSTS = {'auth.example.com', 'api.partner.com'}
def safe_request(url, token):
from urllib.parse import urlparse
host = urlparse(url).hostname
if host not in ALLOWED_HOSTS:
raise ValueError(f'Host {host} is not allowed')
headers = {'Authorization': f'Bearer {token}'}
response = requests.get(url, headers=headers, timeout=5)
return response.json()
4. Leverage Flask middleware for token protection
Use before/after request hooks to ensure tokens are only attached to trusted outgoing calls and to log suspicious activity.
@app.before_request
def attach_bearer_token():
# Example: attach token only for specific blueprints
if request.blueprint in ['api_client']:
g.token = os.getenv('SERVICE_TOKEN')
@app.after_request
def log_outgoing_token_usage(response):
# Audit logging can help detect misuse
if hasattr(g, 'token'):
app.logger.info('Bearer token used for outgoing call')
return response
5. Use the CLI and CI/CD integration for early detection
Run middlebrick scan <url> to identify API endpoints that handle authentication and assess their resilience to network-level attacks. For continuous protection, add the GitHub Action to fail builds if insecure patterns are detected in OpenAPI specs or runtime behavior.