Cors Wildcard in Flask with Basic Auth
Cors Wildcard in Flask with Basic Auth — how this specific combination creates or exposes the vulnerability
A Cross-Origin Resource Sharing (CORS) wildcard (Access-Control-Allow-Origin: *) combined with HTTP Basic Authentication in a Flask application creates a significant security misconfiguration. When a server responds with a wildcard CORS policy while also requiring Basic Auth, it may permit unauthorized cross-origin requests to carry valid authentication credentials.
In Flask, developers sometimes apply a CORS middleware or route-level headers that set Access-Control-Allow-Origin: *. If the same routes also accept and validate Basic Auth credentials (sent via the Authorization: Basic header), browsers will allow the cross-origin request to proceed and expose the authenticated response to the originating site. This violates the principle that wildcard origins should not be used when credentials are involved.
The browser’s CORS implementation treats the combination as dangerous: a webpage served from https://evil.com can make a XMLHttpRequest or fetch call to the authenticated endpoint, and if the server responds with *, the browser delivers the response to the attacker’s script. Even though the request includes an Authorization header, the server may still process it and return sensitive data, thinking the origin is unrestricted.
Consider an authenticated metrics endpoint /api/v1/metrics protected by Basic Auth. If the Flask app sets:
resp = make_response(jsonify(metrics))
resp.headers['Access-Control-Allow-Origin'] = '*'
resp.headers['Access-Control-Allow-Headers'] = 'Authorization'
and also validates the Basic Auth credentials, a malicious site can read the response. This is especially relevant when the Basic Auth credentials are static or shared across services, increasing the risk of accidental exposure.
Attack patterns enabled by this misconfiguration include cross-origin credential theft and unauthorized data access. While this is not a server-side code injection or a traditional OWASP API Top 10 Broken Object Level Authorization (BOLA), it is a dangerous information exposure that can be chained with other weaknesses. Tools like middleBrick can detect such risky header combinations during an unauthenticated scan, highlighting the need for tighter CORS and authentication alignment.
Basic Auth-Specific Remediation in Flask — concrete code fixes
Remediation centers on avoiding wildcard origins when credentials are in use and explicitly allowing only trusted origins. In Flask, you should set Access-Control-Allow-Origin to a specific origin or dynamically reflect a safe origin rather than using *. When Basic Auth is enabled, ensure CORS headers are applied conditionally.
Below are concrete, working Flask examples that implement secure CORS with Basic Auth. The first example uses a simple hardcoded origin; the second demonstrates a dynamic origin check to allow a list of trusted domains.
Example 1: Fixed allowed origin with Basic Auth
from flask import Flask, request, Response, jsonify
import base64
app = Flask(__name__)
VALID_USER = 'admin'
VALID_PASS = 's3cret'
@app.before_request
def authenticate():
if request.path.startswith('/api/'):
auth = request.authorization
if not auth or not (auth.username == VALID_USER and auth.password == VALID_PASS):
return Response('Could not verify your access level.', 401, {'WWW-Authenticate': 'Basic'})
@app.route('/api/metrics')
def metrics():
data = {'cpu': 42, 'memory': 68}
resp = jsonify(data)
resp.headers['Access-Control-Allow-Origin'] = 'https://trusted.example.com'
resp.headers['Access-Control-Allow-Headers'] = 'Authorization'
resp.headers['Access-Control-Allow-Methods'] = 'GET, OPTIONS'
return resp
Example 2: Dynamic origin validation for multiple trusted origins
from flask import Flask, request, Response, jsonify
import base64
app = Flask(__name__)
VALID_USER = 'admin'
VALID_PASS = 's3cret'
TRUSTED_ORIGINS = {'https://app.example.com', 'https://dashboard.example.com'}
def authenticate():
if request.path.startswith('/api/'):
auth = request.authorization
if not auth or not (auth.username == VALID_USER and auth.password == VALID_PASS):
return Response('Unauthorized', 401, {'WWW-Authenticate': 'Basic'})
@app.before_request
def check_auth():
authenticate()
@app.route('/api/metrics')
def metrics():
data = {'cpu': 42, 'memory': 68}
resp = jsonify(data)
origin = request.headers.get('Origin')
if origin in TRUSTED_ORIGINS:
resp.headers['Access-Control-Allow-Origin'] = origin
resp.headers['Access-Control-Allow-Headers'] = 'Authorization'
resp.headers['Access-Control-Allow-Methods'] = 'GET, OPTIONS'
return resp
In both examples, the server validates Basic Auth credentials before returning a response. The CORS header is set to a specific origin from a trusted set, preventing wildcard exposure. For broader integration, teams using the middleBrick CLI can scan their endpoints with middlebrick scan <url> to verify that no wildcard origins appear alongside authentication headers.
Additional best practices include:
- Never set
Access-Control-Allow-Origin: *when endpoints require authentication headers. - Prefer token-based authentication (e.g., OAuth2 or API keys) over Basic Auth for cross-origin scenarios, or ensure credentials are scoped and short-lived.
- Explicitly define
Access-Control-Allow-MethodsandAccess-Control-Allow-Headersto reduce unnecessary exposure. - Use the middleBrick GitHub Action to enforce these rules in CI/CD, failing builds if risky CORS configurations are detected.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |
Frequently Asked Questions
Why is using 'Access-Control-Allow-Origin: *' dangerous with Basic Auth?
How can I test my Flask endpoints for CORS and Basic Auth misconfigurations?
middlebrick scan <your-endpoint-url>. It will report CORS and authentication findings without requiring credentials.