CORS Misconfigurations: The Silent Security Risk in Every SaaS App
CORS (Cross-Origin Resource Sharing) is one of the most misunderstood security mechanisms on the web. Configure it wrong, and attackers can steal your users' data from any website.
How CORS Works (30-Second Version)
Browsers enforce the "Same-Origin Policy" — JavaScript on domain A can't read responses from domain B. CORS is the controlled exception.
When your frontend (app.example.com) makes an API call to your backend (api.example.com), the browser checks if the API explicitly allows requests from app.example.com.
The API signals this via the Access-Control-Allow-Origin header:
Access-Control-Allow-Origin: https://app.example.com
The 4 Most Dangerous CORS Misconfigurations
1. Wildcard Origin With Credentials
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Risk level: CRITICAL
This combination is actually blocked by browsers (they won't send cookies with wildcard origins). But some developers work around it by...
2. Reflecting the Origin Header
// DANGEROUS - reflects any origin
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
next();
});
Risk level: CRITICAL
This effectively allows ANY website to make authenticated requests to your API. An attacker's site at evil.com can read your users' data, modify their accounts, or exfiltrate sensitive information.
The fix: Maintain an explicit allowlist:const allowedOrigins = [
'https://app.example.com',
'https://staging.example.com'
];
app.use((req, res, next) => {
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
}
next();
});
3. Null Origin Allowed
Access-Control-Allow-Origin: null
Risk level: HIGH
The null origin can be triggered from sandboxed iframes, local file pages, and certain redirect sequences. If your API allows it, attackers can exploit it.
null origin in production.
4. Overly Broad Subdomain Matching
// DANGEROUS - any subdomain matches
if (origin.endsWith('.example.com')) {
res.setHeader('Access-Control-Allow-Origin', origin);
}
Risk level: MEDIUM-HIGH
If an attacker can create content on any subdomain (user-generated content, compromised blog, etc.), they can bypass your CORS protection.
The fix: Use exact matching or validate the full origin:const allowedOrigins = new Set([
'https://app.example.com',
'https://admin.example.com'
]);
// Exact match only
if (allowedOrigins.has(origin)) { ... }
What TrustGate Checks
When you scan your application, TrustGate tests:
- ✅ Whether wildcard origins are used
- ✅ Whether the origin header is reflected
- ✅ Whether credentials are exposed to broad origins
- ✅ Whether null origin is allowed
- ✅ Preflight (OPTIONS) response validation
The Bottom Line
CORS configuration should be:
Don't trust frameworks' default CORS settings. Verify them. Scan your app to find CORS issues in seconds.