How to Fix CORS Misconfiguration Security Fix
In this tutorial, you'll learn about How to Fix CORS Misconfiguration Security Fix. We cover key concepts, practical examples, and best practices.
The Problem
Your application has a CORS misconfiguration that allows unauthorized cross-origin requests:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
This combination allows any website to make authenticated requests to your API, enabling cross-site request forgery (CSRF) and data theft.
Quick Fix
1. Never use wildcard with credentials
// Wrong — allows any origin with credentials
app.use(cors({
origin: '*',
credentials: true
}))
// Right — restrict to specific origins
app.use(cors({
origin: 'https://app.example.com',
credentials: true
}))
2. Validate the Origin header
Validate the Origin header against a list of allowed origins:
// Express.js — custom origin validation
const allowedOrigins = [
'https://app.example.com',
'https://admin.example.com',
'https://staging.example.com'
]
app.use(cors({
origin: (origin, callback) => {
// Allow requests with no origin (server-to-server)
if (!origin) return callback(null, true)
if (allowedOrigins.includes(origin)) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
},
credentials: true
}))
3. Restrict exposed headers
// Wrong — exposes all headers
app.use(cors({
exposedHeaders: ['*']
}))
// Right — expose only what is needed
app.use(cors({
exposedHeaders: ['X-Request-Id', 'X-RateLimit-Remaining']
}))
4. Restrict allowed methods
// Wrong — allows all methods
app.use(cors({
methods: '*'
}))
// Right — allow only needed methods
app.use(cors({
methods: ['GET', 'POST', 'PUT', 'DELETE']
}))
5. Set max-age appropriately
// Wrong — no caching, every request sends preflight
app.use(cors())
// Right — cache preflight for 1 hour
app.use(cors({
maxAge: 3600
}))
6. Validate CORS configuration with a test
# Test with the correct origin — should succeed
curl -H "Origin: https://app.example.com" -H "Access-Control-Request-Method: GET" -X OPTIONS -v https://api.example.com/data
# Test with a malicious origin — should fail
curl -H "Origin: https://evil.com" -H "Access-Control-Request-Method: GET" -X OPTIONS -v https://api.example.com/data
7. Use a proxy for cross-origin requests
Instead of opening CORS wide, use a same-origin proxy:
# Nginx — proxy API through the same origin
location /api/ {
proxy_pass https://api.example.com/;
# Browser sees same-origin request, no CORS needed
}
Prevention
- Never use
Access-Control-Allow-Origin: *with credentials. - Maintain an explicit allowlist of allowed origins.
- Validate the
Originheader on every request — do not echo it. - Use a same-origin proxy to avoid CORS entirely when possible.
- Audit CORS configuration regularly with security scanners.
- Log and monitor rejected CORS origins for attack detection.
Common Mistakes with misconfiguration
- Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
- Non-exhaustive pattern matches that compile with warnings then crash at runtime
- Misunderstanding that
Stringis[Char]with poor performance for large text operations
These mistakes appear frequently in real-world CORS code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro