◇ Web Security

CORS Explained: Cross-Origin Resource Sharing and Security

Cross-Origin Resource Sharing, or CORS, is a browser mechanism that allows a server to relax the same-origin policy in a controlled way, permitting selected cross-origin requests to read its responses. It is one of the most misunderstood web platform features, and misconfigurations can expose sensitive data to malicious sites. Understanding how CORS works is essential for building APIs that are both usable across origins and secure.

The Same-Origin Policy and Why CORS Exists

An origin is the combination of scheme, host, and port. The same-origin policy is a fundamental browser rule that prevents a document from one origin from reading responses from another origin. This stops a malicious site from reading your webmail or bank data using your logged-in session.

However, legitimate applications often need to call APIs on other origins, such as a front-end on one domain talking to an API on another. CORS provides a standardized way for a server to tell the browser which other origins are allowed to read its responses, loosening the policy only where the server explicitly opts in.

How CORS Works

CORS is driven by HTTP headers exchanged between the browser and server. The browser adds an Origin header to cross-origin requests, and the server responds with Access-Control-* headers indicating what it permits. The browser, not the server, enforces the result: if the response lacks the right headers, the browser blocks the calling script from reading it.

Simple Requests

Certain low-risk requests, such as a GET or a form-style POST with basic headers, are sent directly. The browser includes the Origin header and checks the response's Access-Control-Allow-Origin before exposing the body to script.

Preflighted Requests

For requests that can change state or use non-simple methods and headers, the browser first sends a preflight using the OPTIONS method to ask permission:

OPTIONS /api/data HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, PUT, POST
Access-Control-Allow-Headers: Content-Type

Only if the preflight response approves the method and headers does the browser send the real request.

Credentialed Requests

By default, cross-origin requests do not include cookies. When an application opts in to sending credentials, the server must respond with Access-Control-Allow-Credentials: true and must specify an exact origin in Access-Control-Allow-Origin. The wildcard * is not allowed together with credentials.

Caching Preflight Responses

Preflight checks add a round trip, so a server can set Access-Control-Max-Age to let the browser cache a preflight result for a period. This improves performance, but it means a policy change may not take effect until cached entries expire, so the value should be chosen deliberately rather than set to a very long duration.

Common CORS Misconfigurations

Because CORS relaxes a security boundary, mistakes can be serious.

  • Reflecting the Origin with credentials. Echoing back any Origin value while also allowing credentials effectively lets every site read authenticated responses. Validate the origin against an allowlist instead.
  • Allowing the null origin. Permitting Origin: null can be abused, because sandboxed documents and some contexts send null.
  • Overly broad wildcards. Using * for internal or authenticated APIs exposes data more widely than intended.
  • Forgetting Vary Origin. When the allowed origin is chosen dynamically, omitting Vary: Origin can cause caches to serve one origin's permissive response to another.

Building a Secure CORS Configuration

  1. Default to closed. Do not enable CORS unless a cross-origin client genuinely needs to read responses.
  2. Use a strict allowlist. Compare the incoming Origin against a known-good list and return that exact value, never a blind reflection.
  3. Be careful with credentials. Only allow credentials for trusted origins, and never combine them with a wildcard.
  4. Scope methods and headers. Permit only the methods and headers the client requires.
  5. Set Vary Origin. Ensure caches distinguish responses per origin.

What CORS Does Not Protect Against

A frequent misconception is that CORS prevents requests from reaching the server. It does not. CORS controls whether the browser lets script read the response; the request may still arrive and cause server-side effects. This is why CORS is not a defense against CSRF, which is about unwanted requests being sent, and why it is unrelated to SSRF, a server-side issue. Server-side authorization and anti-CSRF controls remain necessary regardless of CORS settings. In short, CORS controls who may read a response in the browser, not who may trigger the underlying action, which must always be enforced on the server.

Key Takeaways

  • CORS lets a server selectively relax the same-origin policy so approved origins can read its responses.
  • The browser enforces CORS using the Origin and Access-Control-* headers, with preflight requests for non-simple calls.
  • Credentialed requests require an exact origin and Access-Control-Allow-Credentials: true, never a wildcard.
  • Dangerous misconfigurations include reflecting arbitrary origins with credentials and allowing the null origin.
  • CORS governs reading responses, not sending requests, so it does not replace CSRF protection or server-side authorization.
corsweb-securitybrowser-securityhttp-headersappsec

Frequently asked questions

What is CORS (Cross-Origin Resource Sharing)?

CORS, or Cross-Origin Resource Sharing, is a browser mechanism that uses HTTP headers to let a server allow pages from other origins to read its responses. By default the same-origin policy blocks a page from reading data served by a different origin, and CORS provides a controlled way to relax that restriction. The server declares which origins, methods, and headers are permitted, and the browser enforces the outcome.

How does CORS work?

When a page makes a cross-origin request, the browser adds an Origin header, and the server responds with an Access-Control-Allow-Origin header and related headers indicating whether the origin is permitted. For requests that can change state or use non-simple headers, the browser first sends a preflight OPTIONS request to check what is allowed before sending the real request. If the response headers do not permit the origin, the browser blocks the calling page from reading the result.

How do you configure CORS securely?

Configure CORS by allowing only the specific trusted origins your application needs rather than reflecting arbitrary origins or using a wildcard for sensitive endpoints. Never combine a wildcard with credentialed requests, and return credentials only for explicitly approved origins. Limit the allowed methods and headers to what is required, and treat the allowlist as security-sensitive configuration that is reviewed and kept minimal.

Does CORS protect my server from attacks?

No, CORS is enforced by the browser to protect users, not a server-side access control that protects your data. It governs whether a browser lets one site read another site's responses, but it does nothing against direct requests from tools, scripts, or servers that ignore CORS headers. Your API still needs its own authentication and authorization regardless of CORS settings.

What is the difference between CORS and the same-origin policy?

The same-origin policy is the browser's default restriction that stops a page from reading data from a different origin, where origin is defined by scheme, host, and port. CORS is the standardized mechanism that lets a server selectively relax that policy for specific origins it chooses to trust. In short, the same-origin policy denies cross-origin reads by default, and CORS is how a server can grant controlled exceptions.

Why is a misconfigured CORS policy dangerous?

A misconfigured CORS policy is dangerous because overly permissive settings can let malicious sites read sensitive responses on behalf of a logged-in user. Reflecting any requesting origin while also allowing credentials effectively exposes authenticated data to any website the victim visits. Restricting allowed origins to a vetted list and being careful with credentials prevents this exposure.

Try it hands-on

K0G is an open toolkit of browser-based security utilities — hashing, encoding, JWT, certificates, crypto and more, all running locally in your browser.

Explore the tools →