CORS
debt(d5/e3/b3/t7)
Closest to 'specialist tool catches it' (d5). The term's detection_hints.tools lists semgrep, owasp-zap, and burpsuite — these are all security-focused specialist tools (SAST/DAST) that can detect permissive CORS patterns like wildcard origins or Origin reflection. Standard linters won't catch this; it requires dedicated security scanning.
Closest to 'simple parameterised fix' (e3). The quick_fix indicates validating Origin against an allowlist and returning the specific origin rather than wildcard — this is a focused change to header-setting logic, typically in one middleware or response layer, but requires updating configuration and testing across endpoints.
Closest to 'localised tax' (b3). CORS configuration is typically centralized in middleware or API gateway configuration. The applies_to shows web/api contexts, but the actual implementation burden is confined to a single component (the CORS handler). It doesn't spread throughout the codebase or shape architectural decisions.
Closest to 'serious trap' (t7). The misconception field explicitly states developers believe 'CORS is a security feature that protects the server' when it actually protects the browser/user. This contradicts how developers typically think about server-side security controls. Common_mistakes like reflecting Origin without validation and substring matching for allowlists further demonstrate that the 'obvious' approaches are consistently wrong.
Also Known As
TL;DR
Explanation
Browsers enforce the same-origin policy by default, blocking cross-origin AJAX requests. CORS relaxes this via server-sent headers. Simple requests (GET, POST with safe content types) are sent directly; the browser checks the response headers. Preflighted requests (PUT, DELETE, custom headers) first send an OPTIONS request to check permissions. Misconfigured CORS is one of the most common web security vulnerabilities.
Diagram
sequenceDiagram
participant B as Browser
participant S as Server
Note over B,S: Simple Request - GET/POST safe content-type
B->>S: GET /api/data with Origin header
S-->>B: 200 OK with Access-Control-Allow-Origin
Note over B,S: Preflighted Request - PUT or custom headers
B->>S: OPTIONS /api/data preflight
S-->>B: 204 with Access-Control-Allow-Methods: PUT
B->>S: PUT /api/data actual request
S-->>B: 200 OK
Watch Out
Common Misconception
Why It Matters
Common Mistakes
- Reflecting the incoming Origin header as Access-Control-Allow-Origin without validating against an allowlist.
- Setting Access-Control-Allow-Origin: * with Access-Control-Allow-Credentials: true — browsers block this combination.
- Allowlisting by substring match — evil-yoursite.com passes a check for yoursite.com.
- Not setting Vary: Origin when responses differ by origin — CDNs serve the wrong cached response.
Avoid When
- Do not set Access-Control-Allow-Origin: * on APIs that use cookies or session-based authentication — credentials are never sent with wildcard origins but the misconfiguration signals a broken policy.
- Avoid configuring CORS at the application layer if a gateway or CDN already handles it — duplicate headers break the browser negotiation.
When To Use
- Set Access-Control-Allow-Origin to a specific allowlist of trusted origins — never reflect the incoming Origin header directly.
- Use credentials: true (cookies/auth headers) only when the origin is explicitly trusted and listed — never combine it with a wildcard origin.
- Validate preflight OPTIONS requests and return correct Access-Control-Allow-Methods and Headers to avoid blocking legitimate cross-origin requests.
Code Examples
// Reflecting any Origin — security bypass:
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
header('Access-Control-Allow-Origin: ' . $origin); // Any origin allowed!
header('Access-Control-Allow-Credentials: true');
// Attacker's evil.com can now make authenticated requests
// Validate against allowlist:
$allowed = ['https://app.example.com', 'https://admin.example.com'];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowed, true)) {
header('Access-Control-Allow-Origin: ' . $origin);
header('Access-Control-Allow-Credentials: true');
header('Vary: Origin');
}