Glossary
CORS
Cross-Origin Resource Sharing is the mechanism by which a server tells a browser that another origin is allowed to read its responses. Without it the same-origin policy blocks the read, and the requesting page receives an error even though the request succeeded. It is a relaxation of a browser-enforced restriction, which means it is not access control: a server relying on CORS to keep data private has no protection against anything that is not a browser.
The headers that matter
`Access-Control-Allow-Origin` names the origin permitted to read the response, or `*` for any. Exactly one origin, or the wildcard — a list is not valid.
`Access-Control-Allow-Credentials: true` permits the request to carry cookies and authentication, and the response to be read anyway.
`Access-Control-Allow-Methods` and `Access-Control-Allow-Headers` answer a preflight, stating what the real request may use.
`Access-Control-Expose-Headers` lists which response headers the page may read; by default only a short safe list is available.
`Access-Control-Max-Age` caches the preflight result, avoiding a round trip before every subsequent request.
`Access-Control-Allow-Private-Network` extends the model to requests from a public page into a private network address, which browsers now gate behind an explicit opt-in.
Why the wildcard and credentials conflict
`Access-Control-Allow-Origin: *` with `Access-Control-Allow-Credentials: true` is rejected by browsers, deliberately.
The combination would mean any site could make authenticated requests with the visitor's cookies and read the responses, which is every cross-site attack at once.
Servers wanting credentials must echo a specific origin, which means checking the request's `Origin` header against an allow-list and returning it.
Echoing whatever origin was sent, without checking, is the common implementation of that pattern and is equivalent to the wildcard while appearing to be an allow-list.
Why Vary: Origin is required
A server that returns a different `Access-Control-Allow-Origin` depending on the request's `Origin` is producing a response that varies by that header.
Without `Vary: Origin`, a shared cache stores one response and serves it to requests from other origins, with the wrong permission attached.
The consequence is either a broken integration or, worse, a permission granted to an origin the server never intended.
The header costs nothing and is omitted routinely, which makes it worth checking explicitly on any API behind a CDN.
What CORS is not
It is not authentication or authorisation. The request reached the server and was processed; CORS only decided whether the browser hands the response to the page.
It does not protect an API. Any non-browser client ignores it entirely.
It does not prevent cross-site request forgery. The request is still sent, and a state-changing endpoint is still affected.
A permissive CORS configuration on an endpoint returning personal data is a real finding, because it lets any site read that data using a visitor's own session.
The distinction that resolves most confusion: CORS never stops a request, it stops a read. A logged error about CORS means the server already did whatever the request asked.
Frequently asked questions
- Does CORS protect my API?
- No. It restricts what browser pages may read. Any client that is not a browser ignores it, so authentication is still required.
- Why can I not use a wildcard with credentials?
- Browsers reject that combination because it would let any site make authenticated requests with a visitor's cookies and read the responses.
- Why do I need Vary: Origin?
- Because the response differs by request origin. Without it, a shared cache can serve one origin's permission to a different origin.
Sources
Related
VeriFixScan crawls a site and applies its checks to every page it reaches, keeping the evidence behind each finding. Scanning one website is free.
Scan a website