CORS Headers: Which Sites May Read Your Responses

Browsers enforce a rule called the same-origin policy: a page from one origin, meaning a combination of protocol, domain and port, cannot freely read responses from another origin. That rule protects users, because without it any page could read your mail or your bank data once you were logged in. But it also blocks legitimate uses, such as a web application that deliberately serves an API to trusted partner sites. Cross-Origin Resource Sharing, or CORS, is the mechanism that lets a server relax the rule in a controlled way, by sending headers that name the origins allowed to read its responses. The CORS Checker checks pasted headers for CORS settings and risks, reporting what a server's headers would permit a browser to do.

How it works

The central header is Access-Control-Allow-Origin, which names the origin or origins permitted to read the response. It can name a single specific origin, such as https://partner.example.com, or it can use a wildcard, *, which permits any origin. A second header, Access-Control-Allow-Credentials, says whether the browser may include credentials, such as cookies, in the request, and its value of true is powerful precisely because credentials are what make a cross-origin request sensitive. Further headers govern which methods, such as GET or POST, and which request headers are permitted, and how long a browser may cache the permission, through Access-Control-Max-Age. Together these headers describe a permission, and reading them as a permission, rather than as technical decoration, is the key to judging them.

Where it goes wrong

Preflight requests are the mechanism that makes CORS work for anything beyond a simple request. Before sending a request with a non-simple method or header, the browser first sends an OPTIONS request asking whether the actual request would be permitted, and only proceeds if the server's headers allow it. This is why CORS misconfigurations often appear as failures in the browser console rather than as server errors: the server may be working perfectly, but the browser refuses to send or to expose the response because the headers did not grant permission. A checker that reads pasted headers can show the permission the headers describe, but it cannot simulate a browser's preflight decision for a specific request, which also depends on the request's method and headers.

Worked example

Worked example with sample values. Suppose you paste a sample set of 4 headers: Access-Control-Allow-Origin: *, Access-Control-Allow-Credentials: true, Access-Control-Allow-Methods: GET, POST, and Access-Control-Max-Age: 86400. Counting the CORS headers gives 4 in total, and the critical finding is the combination of the first two: a wildcard origin together with credentials. That combination is dangerous, because it invites any origin to make credentialed requests, and browsers in fact refuse to honour a wildcard with credentials, so the permission may fail in practice as well as being risky in intent. Converting the cache lifetime gives 86400 divided by 3600, which equals 24 hours, so a browser may cache this permission for a full day. The safe replacement for the sample is a single named origin, with credentials only if that origin genuinely needs them. The sample headers here are illustrative, not captured from a live server.

Mistakes to avoid

The most important misunderstanding about CORS is that it is an access control for the server. It is not. CORS headers are enforced by browsers, and a non-browser client, such as a script run directly, can ignore them entirely and read any public response. A server that relies on CORS to protect sensitive data is therefore unprotected against anyone who does not use a browser, which is exactly who an attacker is. Real protection for sensitive endpoints comes from authentication, authorisation and server-side checks, with CORS as an additional browser-facing layer that prevents ordinary web pages from abusing a visitor's logged-in session. A wildcard origin on a public, unauthenticated API may be reasonable; the same wildcard on an authenticated API is a serious error.

Putting it into practice

Use the checker when reviewing an API's headers, especially before exposing an endpoint to partner sites. Paste the headers, read the allowed origin first, and check whether credentials are permitted and whether the combination is safe. Replace wildcards with named origins wherever credentials or sensitive data are involved, keep the method and header lists as narrow as the API needs, and set a cache lifetime that reflects how often the permission should be revisited. Then test in a browser, since pasted headers cannot show the preflight behaviour for a real request. CORS is a small set of headers with large consequences, and reading them as permissions is the habit that keeps those consequences under control.

Related tools and reading: the DNS Lookup and the JSON Studio cover neighbouring checks that pair naturally with this one, and the guide at [/blog/http-security-headers-guide/] extends the same topic with further background and examples for readers who want to go deeper.

Key points

  • Allowed origin named specifically for sensitive APIs
  • Wildcard origin never combined with credentials
  • Methods and headers limited to what the API needs
  • Cache lifetime understood as hours, not an abstract number
  • Server-side authentication kept as the real access control

In short: CORS controls which origins may read a response in a browser. The checker examines pasted headers for CORS settings and risks. A wildcard origin with credentials is a dangerous combination. CORS is a browser rule, not a server access control.

One habit ties all of this together: re-check after every change. A result from the CORS Checker is only as current as the text it was run on, so a fix, a redesign, or a new version of the underlying material deserves a fresh run rather than reliance on an old report. Keep the previous result alongside the new one, note what changed between them, and treat any new finding as a question to investigate rather than a verdict to accept or dismiss. That loop of checking, fixing, re-checking and recording is what turns a one-off test into a reliable routine, and it costs far less time than debugging a problem that a second check would have caught early.