RoastMyOpsec

Vulnerabilities

CORS Wildcard vs Allowlist for Public APIs

September 30, 2022

CORS wildcard vs allowlist is a trust-boundary choice for browser-called APIs, not a performance tweak. Access-Control-Allow-Origin: * is acceptable only for responses that are meant to be read by any website and that do not ride on cookies or client certificates. If the API uses credentials, reflect an exact allowlisted origin or reject the request. Wildcard plus Allow-Credentials is invalid in browsers and is a policy smell even when clients refuse it. RoastMyOpsec's app-mode CORS check sends a bounded GET/OPTIONS with an untrusted Origin — no credential stuffing, no authenticated abuse.

The practical difference

CORS is a browser rule. Other websites' JavaScript may not read your API response unless you opt in. Non-browser clients ignore CORS entirely, so it is not a substitute for authentication.

A wildcard says 'any origin may read this.' An allowlist says 'only these HTTPS origins may.' Reflecting whatever Origin arrived is usually worse than a static * because it looks like a tailored yes to an attacker site.

How to choose based on the API

Start with whether the response contains anything a stranger's page should not see. Public marketing JSON can often use *. Account, billing, and admin APIs cannot. If the browser will send cookies, you need Allow-Credentials and a specific origin — never *.

API jobACA-OriginCredentialsTakeaway
Public, no cookies* or a short allowlistOffWildcard is a product choice, not a footgun
Same-site SPA + APIExact app originOn only if you actually use cookiesPrefer same-origin and skip CORS entirely
Partner widgetNamed partner originsUsually off; tokens in Authorization insteadDo not copy the partner list onto admin routes
Reflect any OriginAttacker-controlledEspecially bad if onThis is the classic miss

When a wildcard still fails OPSEC

Wildcard on a JSON error body that includes stack traces or account ids leaks through any website that can trigger the request. Combine boring errors with a tight origin policy.

If you do not need cross-origin browser reads, omit CORS headers. Absence is safer than a generous default copied from a tutorial.

Common mistakes

The first mistake is Access-Control-Allow-Origin: * plus Access-Control-Allow-Credentials: true.

The second mistake is echoing the Origin header with no allowlist.

The third mistake is setting CORS on the marketing site and forgetting the API host that actually holds sessions.

Free audit the URL you own

RoastMyOpsec is a defensive public-surface roast: headers, cookies, sensitive paths, and more — no exploit payloads. Start with the free audit, then open the vault if the blurred findings look expensive.

Free audit now

FAQ

Is Access-Control-Allow-Origin * always a vulnerability?
No. It is appropriate for public, credential-free resources. It is a miss on APIs that return private data or that expect cookies.
Does CORS replace API authentication?
No. CORS only affects browsers. Authenticate and authorize every request as if any client on the internet can call the URL.
How does RoastMyOpsec test CORS?
App mode sends a bounded request with an untrusted Origin and reads ACAO / credentials behavior. It does not send your users' cookies or attempt account takeover.

Sources

Related guides