CORS headers configured with specific allowed origins
Why it matters
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.
Severity rationale
Medium because exploiting CORS misconfigurations requires a victim to visit an attacker-controlled page, reducing reach but enabling session-riding attacks against authenticated users.
Remediation
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)
Detection
-
ID:
cors-configured -
Severity:
medium -
What to look for: Enumerate every relevant item. Check the CORS middleware or headers configuration. Verify that
Access-Control-Allow-Originis set to specific, trusted domains rather than*(wildcard). IfAccess-Control-Allow-Origin: *is used withAccess-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 withAccess-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')) } } }))
External references
- cwe · CWE-942 — Permissive Cross-domain Policy with Untrusted Domains
- cwe · CWE-352 — Cross-Site Request Forgery (CSRF)
- owasp:2021 · A05 — Security Misconfiguration
- owasp:2023 · API8 — Security Misconfiguration
Taxons
History
- 2026-04-18·v1.0.0·Initial import from api-security·automated