← All cybersecurity posts

CORS Misconfiguration: How It Exposes Your API

Cross-Origin Resource Sharing (CORS) controls which websites can read responses from your API in a user's browser. Configured well, it is invisible. Configured badly, it lets any website read your users' private data while they are logged in.

How CORS works

Browsers enforce the same-origin policy: a page on evil.example cannot read responses from api.example.com. CORS lets your server relax this for trusted origins using response headers:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true

When credentials are allowed, the browser sends cookies with the request and lets the allowed origin read the response.

The dangerous misconfigurations

Reflecting any Origin with credentials

The server copies the request's Origin header into Access-Control-Allow-Origin and sets Allow-Credentials: true. Any website can now make authenticated requests and read the responses.

// Vulnerable
res.setHeader("Access-Control-Allow-Origin", req.headers.origin);
res.setHeader("Access-Control-Allow-Credentials", "true");

Weak origin validation

Checks like origin.endsWith("example.com") allow attackerexample.com. Checks like origin.includes("example.com") allow example.com.attacker.net.

Trusting null

Some servers allow Origin: null. Attackers can produce a null origin from sandboxed iframes, so trusting it is like trusting everyone.

Trusting every subdomain

Allowing *.example.com means any XSS or takeover on any subdomain, such as an old marketing site, can read your API data.

What about Access-Control-Allow-Origin: *?

A wildcard is fine for truly public, unauthenticated data. Browsers do not allow the wildcard together with credentials. The risk comes from dynamic reflection, not the static wildcard.

How to configure CORS correctly

  1. Maintain an explicit allowlist of exact origins.
  2. Compare the full origin exactly, including scheme and port.
  3. Only allow credentials where the frontend genuinely needs cookies.
  4. Never allow null.
  5. Add Vary: Origin to responses so caches do not serve one origin's CORS headers to another.
  6. Avoid CORS entirely where possible by serving the frontend and API from the same origin, or proxying API calls.
const ALLOWED = new Set(["https://app.example.com", "https://admin.example.com"]);
const origin = req.headers.origin;
if (ALLOWED.has(origin)) {
  res.setHeader("Access-Control-Allow-Origin", origin);
  res.setHeader("Access-Control-Allow-Credentials", "true");
  res.setHeader("Vary", "Origin");
}

CORS is not access control

CORS only affects browsers. Attackers using curl or scripts ignore it entirely. Your API must still authenticate and authorise every request.

Testing CORS

SecurityInfinity agents send requests with crafted origins, including lookalike domains, null and subdomains, and verify whether authenticated responses become readable. Start free.

Frequently asked questions

Can CORS misconfiguration lead to account takeover?

Yes, if an attacker can read responses containing tokens, API keys or data that allows them to change account settings.

Does CORS protect against CSRF?

Not fully. CORS controls reading responses, but simple cross-site requests can still be sent. Use CSRF protections as well.

Is a wildcard origin always insecure?

No. It is acceptable for public data without credentials. It is dangerous only when combined with sensitive or authenticated responses.

Find what attackers can see, before they do.

AI pentesting agents test your web app, API and cloud, and every finding comes with evidence and a fix. First report in about 10 minutes.

Stay ahead of attackers.

New vulnerabilities, breach write-ups and practical fixes. A few emails a month.