{
    "slug": "cors_deep_dive",
    "term": "CORS",
    "category": "networking",
    "difficulty": "intermediate",
    "short": "Cross-Origin Resource Sharing — the browser mechanism that controls which cross-origin requests are permitted, using HTTP headers negotiated between client and server.",
    "long": "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.",
    "aliases": [
        "Cross-Origin Resource Sharing",
        "CORS policy"
    ],
    "tags": [
        "cors",
        "security",
        "http",
        "api",
        "networking"
    ],
    "misconception": "CORS is a security feature that protects the server — it actually protects the user's browser; a server-side attacker is unaffected by CORS.",
    "why_it_matters": "Permissive CORS configuration turns the browser's same-origin policy off, allowing malicious sites to make authenticated API calls on behalf of the victim.",
    "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."
    ],
    "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."
    ],
    "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."
    ],
    "related": [
        "cors_misconfiguration",
        "same_site_cookie",
        "csrf",
        "security_headers"
    ],
    "prerequisites": [
        "cors_misconfiguration",
        "api_design",
        "http_methods_idempotency"
    ],
    "refs": [
        "https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS",
        "https://portswigger.net/web-security/cors"
    ],
    "bad_code": "// Reflecting any Origin — security bypass:\n$origin = $_SERVER['HTTP_ORIGIN'] ?? '';\nheader('Access-Control-Allow-Origin: ' . $origin); // Any origin allowed!\nheader('Access-Control-Allow-Credentials: true');\n// Attacker's evil.com can now make authenticated requests",
    "good_code": "// Validate against allowlist:\n$allowed = ['https://app.example.com', 'https://admin.example.com'];\n$origin = $_SERVER['HTTP_ORIGIN'] ?? '';\nif (in_array($origin, $allowed, true)) {\n    header('Access-Control-Allow-Origin: ' . $origin);\n    header('Access-Control-Allow-Credentials: true');\n    header('Vary: Origin');\n}",
    "example_note": "The bad example copies any Origin straight into the response header — an attacker's domain receives authenticated API responses. The fix checks the origin against an explicit allowlist before echoing it.",
    "quick_fix": "Never set Access-Control-Allow-Origin to * for authenticated endpoints; always validate the Origin header against an allowlist and return the specific origin, not the wildcard",
    "severity": "high",
    "effort": "medium",
    "created": "2026-03-15",
    "updated": "2026-03-31",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/cors_deep_dive",
        "html_url": "https://codeclaritylab.com/glossary/cors_deep_dive",
        "json_url": "https://codeclaritylab.com/glossary/cors_deep_dive.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[CORS](https://codeclaritylab.com/glossary/cors_deep_dive) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/cors_deep_dive"
            }
        }
    }
}