CORS

CORS with credentials and a wildcard: the worst combination

What CORS is actually for

By default, a browser stops JavaScript on evil.com from reading responses your API sends to a request — that is the same-origin policy doing its job. CORS (Cross-Origin Resource Sharing) is how your server says 'actually, these specific other origins are allowed to read my responses.' Used correctly, it is a precise guest list.

The trouble starts when the guest list says 'everyone' and the front door also hands out your house keys.

The two ingredients of the bad combination

Two response headers matter here:

  • Access-Control-Allow-Origin — which sites may read the response.
  • Access-Control-Allow-Credentials: true — whether the browser may send and expose cookies, auth headers and the like on cross-origin requests.

Individually, each is fine. Together, with an open origin, they are the problem. If you allow any origin and also allow credentials, then a malicious site a logged-in user visits can call your API with that user's cookies attached and read the response — their account, their data, through your own authentication.

The wildcard you cannot actually use

Browsers know this is dangerous, so they enforce one rule: you cannot combine a literal Access-Control-Allow-Origin: * with Access-Control-Allow-Credentials: true. The request fails. Good.

The catch is what developers do to work around that error. To support credentials, the origin must be a specific value — so a common shortcut is to read the incoming Origin header and echo it straight back. That passes the browser check, but it means every origin is allowed, because whatever asks gets approved. You have rebuilt the wildcard, just in a form the browser no longer blocks. This reflected-origin-plus-credentials pattern is the genuinely risky one.

How to configure CORS safely

  • Use an explicit allowlist. Keep a fixed set of trusted origins (your own front-ends, known partners) and only reflect an origin back if it is on that list.
  • Do not reflect arbitrary origins. If your code copies the request Origin into the response without checking it, that is the bug.
  • Only enable credentials when you need them. If the endpoint does not require cookies or auth, leave Access-Control-Allow-Credentials off entirely.
  • Be specific with methods and headers too, rather than allowing everything by reflex.
  • Remember CORS is not authorization. It governs cross-origin reads in browsers; your server must still authenticate and authorize every request on its own.

The honest part

This is an easy one to get wrong, especially when you are fighting a CORS error during development and the fastest fix is to open everything up. That temporary fix has a way of shipping to production and staying there.

Check what your API allows

You cannot see your CORS headers by looking at your site — they live in the responses, not the page. An automated scan inspects the actual Access-Control-* headers your endpoints return and flags an origin policy that is too permissive for the credentials you send. Scan your site and find out whether your API is quietly open to every origin.

Related reading

FAQ

Why does the browser block wildcard with credentials but not a reflected origin?
The browser refuses a literal '*' together with credentials as a hard rule. Reflecting the request's Origin header passes that check because the value is a specific origin — but since you echo back whatever asks, it is effectively the same open policy, just one the browser cannot catch for you.
Is it ever safe to allow all origins?
Only for genuinely public, non-credentialed data — like an open read-only API with no cookies or auth involved. The moment credentials are in play, you must use an explicit allowlist of trusted origins instead.
Does CORS protect my API from attackers directly?
Not on its own. CORS only governs which browser origins may read your responses; it is not authentication or authorization. A tool or script can still call your API regardless of CORS, so your server must enforce access control independently.