5 min read

CORS misconfiguration — how `Access-Control-Allow-Origin: *` breaks your app

CORS is one of the most misunderstood security headers. Here is exactly when `*` is safe, when it is catastrophic, and how to configure CORS correctly for a Next.js + Supabase stack.

CORS (Cross-Origin Resource Sharing) governs whether a browser at origin A is allowed to read a response from origin B. Misconfiguration ranges from "your API is unusable" to "any website can read your authenticated user's data".

What it is

Browsers enforce the same-origin policy by default — JavaScript on A cannot read responses from B. CORS is the opt-in mechanism where B declares which origins may read its responses. `Access-Control-Allow-Origin: *` means "anyone", `Access-Control-Allow-Origin: https://app.example.com` means "just this origin".

Vulnerable example

// Vulnerable combination:
export async function GET() {
  return new Response(JSON.stringify(await getUserProfile()), {
    headers: {
      "Access-Control-Allow-Origin": "*",               // <- anyone can read
      "Access-Control-Allow-Credentials": "true",       // <- with cookies!
    },
  });
}
// This combination is REJECTED by browsers, but the mistake pattern keeps coming up.

Fixed example

// Fixed: explicit allowlist + credentials
const ALLOWED_ORIGINS = new Set([
  "https://app.yourdomain.com",
  "https://www.yourdomain.com",
]);

export async function GET(req: Request) {
  const origin = req.headers.get("origin") ?? "";
  const ok = ALLOWED_ORIGINS.has(origin);
  return new Response(JSON.stringify(await getUserProfile()), {
    headers: {
      "Access-Control-Allow-Origin": ok ? origin : "",
      "Access-Control-Allow-Credentials": ok ? "true" : "false",
      "Vary": "Origin",
    },
  });
}

How Securie catches it

Securie scans every response-setter in your codebase for CORS headers. Combinations that allow credentialed access from untrusted origins are flagged critical.

Checklist

  • Never combine `Access-Control-Allow-Origin: *` with `Access-Control-Allow-Credentials: true`
  • Maintain an allowlist of explicit origins; do not echo back the request origin without validating
  • Set `Vary: Origin` when the response depends on the request origin (for CDN correctness)
  • Preflight responses are short-cached — test with realistic cache settings
  • Public APIs (no cookies, no auth headers) may use `*`

FAQ

Is CORS a security feature?

Partially. CORS protects users from cross-site data reads but does not protect your server from any attack. CSRF is a separate concern.