A CORS wildcard (Access-Control-Allow-Origin: *) combined with Access-Control-Allow-Credentials: true is a configuration that browsers reject — but the attempt signals a misunderstanding of CORS that often accompanies other auth mistakes. The real risk is a permissive CORS policy that allows arbitrary origins with credentials: CWE-942 (Permissive Cross-domain Policy) and CWE-352 (CSRF) describe how this enables cross-site request forgery against cookie-authenticated APIs. OWASP API8 (Security Misconfiguration) covers CORS as a first-class misconfiguration class. Attackers host malicious pages that call your API with the victim's session cookie — the browser delivers it because your CORS policy permits the attacker's origin.
Medium because exploiting CORS misconfigurations requires a victim to visit an attacker-controlled page, reducing reach but enabling session-riding attacks against authenticated users.
Explicitly enumerate allowed origins in src/middleware.ts or your framework's CORS config. Never reflect the request Origin header back without validating against a known-good list.
// next.config.js (Next.js headers)
module.exports = {
async headers() {
return [{
source: '/api/:path*',
headers: [
{ key: 'Access-Control-Allow-Origin', value: 'https://app.example.com' },
{ key: 'Access-Control-Allow-Credentials', value: 'true' },
{ key: 'Access-Control-Allow-Methods', value: 'GET,POST,PUT,DELETE,OPTIONS' }
]
}]
}
}
// For dynamic multi-tenant origins, validate against an allowlist:
const ALLOWED = new Set(['https://app.example.com', 'https://staging.example.com'])
const origin = req.headers.get('origin') ?? ''
if (ALLOWED.has(origin)) res.headers.set('Access-Control-Allow-Origin', origin)
ID: api-security.input-validation.cors-configured
Severity: medium
What to look for: Enumerate every relevant item. Check the CORS middleware or headers configuration. Verify that Access-Control-Allow-Origin is set to specific, trusted domains rather than * (wildcard). If Access-Control-Allow-Origin: * is used with Access-Control-Allow-Credentials: true, it is insecure.
Pass criteria: At least 1 of the following conditions is met. CORS headers specify allowed origins explicitly. If a wildcard is used, credentials are not allowed in requests. Alternatively, origins are dynamically validated against a whitelist.
Fail criteria: Access-Control-Allow-Origin: * is combined with Access-Control-Allow-Credentials: true, or the allowed origin is the wildcard without credentials check.
Skip (N/A) when: The API is not accessed from browsers (e.g., server-to-server API only).
Detail on fail: "CORS headers allow all origins with wildcard and credentials: Access-Control-Allow-Origin: * with Access-Control-Allow-Credentials: true" or "CORS not configured — requests from different origins will be blocked"
Remediation: Configure CORS to allow specific origins:
import cors from 'cors'
app.use(cors({
origin: ['https://example.com', 'https://app.example.com'],
credentials: true
}))
Or for dynamic origin validation:
const allowedOrigins = ['https://example.com', 'https://app.example.com']
app.use(cors({
origin: (origin, callback) => {
if (allowedOrigins.includes(origin)) {
callback(null, true)
} else {
callback(new Error('CORS not allowed'))
}
}
}))