Cross-Origin Resource Sharing (CORS) is a browser security mechanism that controls how web pages can request resources from a different domain. When misconfigured, it can allow any website on the internet to make authenticated requests to your API on behalf of your users — effectively bypassing the Same-Origin Policy that browsers enforce by default.
How CORS Works
Browsers enforce the Same-Origin Policy (SOP): JavaScript on attacker.com cannot read the response from a request made to api.yoursite.com. CORS is the mechanism that selectively relaxes this restriction when you legitimately want cross-origin requests (for example, your frontend on app.yoursite.com calling your API on api.yoursite.com).
For "simple" cross-origin requests, the browser attaches an Origin header. The server responds with Access-Control-Allow-Origin. If they match, the browser gives the page access to the response. For non-simple requests (those using methods like PUT or DELETE, or custom headers), the browser first sends a "preflight" OPTIONS request to verify permission.
The Dangerous Misconfigurations
1. Wildcard with Credentials
Using Access-Control-Allow-Origin: * with Access-Control-Allow-Credentials: true is technically invalid (browsers reject it), but some frameworks silently strip the credentials header. More importantly, the intent — to allow any origin to access credentialed resources — is fundamentally broken.
# Broken and dangerous intent:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
2. Reflecting the Origin Header
The most common exploitable misconfiguration: the server dynamically reflects whatever Origin header it receives, combined with Access-Control-Allow-Credentials: true. This allows any site to make authenticated requests to your API.
# Request from attacker.com:
Origin: https://attacker.com
# Vulnerable server response:
Access-Control-Allow-Origin: https://attacker.com
Access-Control-Allow-Credentials: true
An attacker's page can now make a request to your /api/profile endpoint, and the browser will include the victim's cookies. The attacker's JavaScript can read the full response.
3. Weak Origin Validation
Some implementations validate the origin with a prefix match or substring check:
# Intended: only allow yoursite.com
# Actual: allows yoursite.com.evil.com
if origin.startswith('https://yoursite.com'):
allow_origin = origin
Always validate the full origin against an exact allowlist.
4. Trusting Null Origin
Browsers send Origin: null for requests from sandboxed iframes, file:// URLs, and some redirects. Allowing null origin is equivalent to a wildcard in many scenarios.
# Never do this:
Access-Control-Allow-Origin: null
How to Configure CORS Correctly
Maintain an Explicit Allowlist
Validate the incoming Origin header against a hardcoded list of legitimate origins. Only reflect origins that are on the list.
ALLOWED_ORIGINS = {
'https://app.yoursite.com',
'https://yoursite.com',
}
def cors_origin(request_origin):
if request_origin in ALLOWED_ORIGINS:
return request_origin
return None # Do not set the header
Be Restrictive with Methods and Headers
Only allow the HTTP methods your API actually uses. Do not use Access-Control-Allow-Methods: *.
Access-Control-Allow-Origin: https://app.yoursite.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
Never Use Wildcards with Credentials
If you need credentialed cross-origin requests, you must use an explicit, validated origin. Wildcards and credentials are mutually exclusive.
Separate Public and Credentialed APIs
If some endpoints are truly public (no authentication needed), those can use Access-Control-Allow-Origin: * without credentials. For authenticated endpoints, require explicit origin validation.
Testing for CORS Misconfiguration
To test manually, send a request with a crafted Origin header and inspect the response:
curl -sI https://api.yoursite.com/profile -H "Origin: https://evil.com" -H "Cookie: session=your_session_token" | grep -i "access-control"
If the response contains Access-Control-Allow-Origin: https://evil.com and Access-Control-Allow-Credentials: true, the endpoint is vulnerable. Automated scanning tools check for origin reflection and null origin acceptance as part of a standard security assessment.