CORS: how it works, and how it is misconfigured
CORS (cross-origin resource sharing) is how a server tells browsers that pages from other origins may read its responses. By default a browser lets a page read only responses from its own origin, the same-origin policy; CORS headers relax that rule for chosen origins. A CORS misconfiguration relaxes it too far, so any website a signed-in user visits can read that user's data from your API.
Quick facts
- Stands for
- Cross-origin resource sharing
- Defined in
- The WHATWG Fetch Standard; origins in RFC 6454
- Weakness
- CWE-942: permissive cross-domain policy with untrusted domains
- OWASP category
- A02:2025 Security Misconfiguration, which lists CWE-942 (A02 page); see security misconfiguration
- Does a WAF stop it?
- No. CORS is decided by response headers and enforced by the browser
A practical walk-through of the headers is on MDN.
The same-origin policy, and what CORS changes
An origin is the combination of scheme, host and port: https://shop.example and https://api.example are different origins. Browsers let a page send requests to any origin, but read the response only from its own. That rule is what stops a random website from reading your email or bank balance through your signed-in browser.
CORS is a controlled exception. The server answers with headers naming which origins may read the response, and the browser enforces it. CORS never protects the server: it decides what pages in a browser may read, and tools outside a browser ignore it.
How CORS works
Origin. The browser adds this header to cross-origin requests, naming the page's origin.Access-Control-Allow-Origin. The server names one origin that may read the response, or*for any origin.Access-Control-Allow-Credentials: true. Allows the response to be read when the request carried cookies; browsers refuse this together with*.- Preflight request. For methods other than GET, HEAD and simple POST, or with custom headers, the browser first sends an
OPTIONSrequest and proceeds only if the answer allows it. Access-Control-Allow-Methodsand-Headers. The preflight answer listing what the real request may use.
If the response names a different origin, or none, the browser still receives it but refuses to hand it to the page. That refusal is what developers see as a CORS error.
What a CORS error means
A message such as “blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present” means the browser did its job: the server did not say the page's origin may read the response. The request may well have reached the server and run; only the reading was blocked.
The fix is on the server that owns the resource: return the right Access-Control-Allow-Origin for the origins that legitimately call it, and answer preflight requests. Browser extensions that switch CORS off, or a proxy that adds * to everything, make the error disappear by removing the protection.
Dangerous CORS misconfigurations
- Reflecting any Origin with credentials. The server copies whatever arrives in
Origininto the allow header and addsAllow-Credentials: true. Any website can now read a signed-in user's data. - Loose matching. A check that the origin ends with
example.comalso acceptsattacker-example.com; one that it starts with it acceptsexample.com.attacker.net. - Allowing the null origin. Sandboxed frames and local files send
Origin: null, and attackers can produce it on purpose. - Trusting every subdomain. One forgotten subdomain with an XSS flaw then becomes a way to read the main API.
- Allowing plain HTTP origins. An attacker on the network can inject script into the HTTP page, which the HTTPS API then trusts.
A wildcard * on public data that needs no sign-in is fine. The danger is always in combining a permissive origin with responses that depend on who the user is.
CORS is not a CSRF defence
CORS controls reading, not sending. A cross-site form can still submit to your site, and the browser will still attach cookies according to their SameSite setting; CORS only decides whether the attacker's page can see the answer. Protection against forged actions comes from CSRF tokens and SameSite cookies.
A strict CORS policy does make some requests harder to forge, because a preflight stops JSON requests with custom headers from other origins. That is a side effect, not a design you should rely on.
How to configure CORS safely
- Keep an explicit allowlist. Compare the full origin, scheme and port included, against a fixed list.
- Send credentials only where needed. Most cross-origin calls do not need cookies; leave
Allow-Credentialsoff unless they do. - Never reflect Origin unchecked, and never allow null. Both are equivalent to allowing everyone.
- Add
Vary: Origin. When the allow header depends on the request, caches must not serve one origin's answer to another. - Return CORS headers only on endpoints called cross-origin. Not site-wide; the broader header set is on security headers.
What a WAF can do about CORS
Almost nothing. A CORS misconfiguration is in the response headers your server sends, and its effect happens inside the victim's browser when another site reads the response. The requests involved are ordinary requests with an Origin header.
Finding it is a matter of testing: send requests with unusual Origin values and read what comes back in Access-Control-Allow-Origin. The fix is a line of configuration in the application or the server in front of it.
Questions
What is CORS?
Cross-origin resource sharing is a set of HTTP headers that lets a server tell browsers which other origins may read its responses, relaxing the same-origin policy for chosen sites.
What does a CORS error mean?
The browser received a response but refused to give it to the page, because the server did not list the page's origin as allowed to read it. The fix is on the server that owns the resource.
What is a preflight request?
An OPTIONS request the browser sends before a cross-origin request with a non-simple method or custom headers, asking the server whether the real request is allowed.
Is Access-Control-Allow-Origin: * dangerous?
Not on public data that needs no sign-in. Browsers refuse to combine it with credentials. The danger is reflecting any origin, or a loosely matched one, together with credentials.
Does CORS protect against CSRF?
No. CORS controls whether a page can read a response, not whether a request is sent. CSRF needs tokens and SameSite cookies.