CORS Headers and Cross-Origin Security
How Cross-Origin Resource Sharing headers let browsers safely relax the same-origin policy for specific requests.
Core Concept
CORS headers let a server explicitly permit web pages from other origins to make requests to it, relaxing the browser's default same-origin policy under controlled conditions.
Without CORS, browsers block cross-origin requests by default as a security measure — CORS is the opt-in mechanism for legitimate exceptions.
Key CORS Headers
A handful of response headers control exactly what cross-origin access is permitted.
- Access-Control-Allow-Origin — which origins may access the response
- Access-Control-Allow-Methods — which HTTP methods are permitted
- Access-Control-Allow-Credentials — whether cookies can be included
- Access-Control-Allow-Headers — which custom headers are permitted
Wildcard Limitation
Access-Control-Allow-Origin: * cannot be combined with Allow-Credentials: true — browsers reject that combination since it would expose credentialed data too broadly.
Simple vs Preflighted Requests
Not every cross-origin request triggers the same CORS handshake.
- Simple requests — basic GET/POST with standard headers, no preflight
- Preflighted requests — trigger an OPTIONS request first for verification
- Preflight caches its result briefly via Access-Control-Max-Age
Common CORS Misconfigurations
CORS mistakes tend to fall into two opposite failure modes: overly restrictive, breaking legitimate use, or overly permissive, creating a security gap.
Reflecting the request's Origin header back verbatim as Allow-Origin, without validating it against an allowlist, effectively disables the protection entirely.
Reflected Origin Risk
Blindly reflecting any Origin header back in Allow-Origin combined with Allow-Credentials creates a serious cross-origin data exposure risk.
Designing a Safe CORS Policy
A few principles keep CORS configuration both functional and secure.
- Use an explicit allowlist rather than reflecting arbitrary origins
- Avoid combining wildcard origins with credentialed requests
- Scope allowed methods and headers to only what's actually needed
Real-World Implementation
CORS configuration is a routine part of building any API consumed by browser-based clients.
- Public APIs offering broad, credential-free CORS access
- Internal APIs restricting access to specific known frontends
- Security reviews flagging overly permissive CORS as a finding
Testing CORS behavior directly, rather than assuming it works from reading the configuration alone, catches the subtle mismatches that cause real-world breakage.
Common Mistakes to Avoid
A few common mistakes create real CORS security gaps.
- Reflecting the request's Origin header back verbatim without validating against an allowlist.
- Combining a wildcard origin with Allow-Credentials, which browsers reject anyway.
- Misconfiguring the preflight response, silently blocking otherwise correct requests.
- Assuming CORS is enforced server-side rather than entirely by the browser.
- Scoping allowed methods and headers more broadly than actually necessary.
- Overlooking that credentials mode must be explicitly set on the client side too.
- Assuming CORS errors always originate from server misconfiguration rather than client code.
- Failing to test preflight behavior specifically, not just the final actual request.
- Overlooking that some browsers cache preflight results longer than the configured Max-Age.
- Assuming CORS applies to same-origin requests, which it explicitly does not.
- Failing to test CORS behavior with actual credentialed requests, not just simple ones.
- Overlooking that some browser privacy features can affect how cross-origin requests are handled.
Best Practices Checklist
These practices lead to a CORS configuration that's both functional and secure.
- Use an explicit allowlist of trusted origins rather than reflecting arbitrary ones.
- Avoid combining wildcard origins with credentialed requests.
- Scope allowed methods and headers to only what's genuinely needed.
- Test CORS behavior directly across real client scenarios, not just by reading configuration.
- Review preflight response configuration carefully when debugging blocked requests.
- Configure credentials mode explicitly on both the client request and server response.
- Check client-side fetch or XHR configuration when diagnosing an unexpected CORS error.
- Test preflight OPTIONS behavior directly, separate from the actual intended request.
- Verify actual browser preflight caching behavior against your configured Access-Control-Max-Age.
- Remember CORS is exclusively a cross-origin mechanism, irrelevant to same-origin requests.
- Test CORS configuration specifically with credentialed requests, not only simple unauthenticated ones.
- Test CORS behavior under default privacy settings, since some browser features can affect cross-origin request handling.
Frequently Asked Questions
Frequently asked questions about CORS headers.
Is CORS enforced by the server or the browser?
It's enforced entirely by the browser — the server still processes the request, but the browser blocks the response from reaching the calling script if it violates policy.
Why can't Access-Control-Allow-Origin: * be combined with credentials?
Browsers reject that combination since it would expose credentialed data too broadly across any origin.
What triggers a CORS preflight request?
Requests using methods or headers beyond the simple defaults, such as custom headers or certain HTTP methods, trigger an OPTIONS preflight first.
What's the risk of reflecting the Origin header back verbatim?
Without allowlist validation, it can create a serious cross-origin data exposure risk, especially when combined with credentialed requests.
Why would a request fail even though the main endpoint's CORS looks correct?
A misconfigured preflight response can silently block the actual request even when the main endpoint itself is configured correctly.
Is server configuration always the cause of a CORS error?
Not always — client-side request configuration, like missing credentials mode settings, can also produce CORS-related failures.
Does credentials mode need to be set on both sides of a CORS request?
Yes — both the client's request configuration and the server's Access-Control-Allow-Credentials header need to align correctly.
Should preflight requests be tested separately from the main request?
Yes — a misconfigured preflight response can silently block the actual request even when the main endpoint is configured correctly.
Does browser preflight caching always match the configured Max-Age exactly?
Not always precisely — browsers can impose their own caching ceiling regardless of a longer configured Max-Age value.
Does CORS apply to requests within the same origin?
No — CORS is specifically a cross-origin mechanism and has no effect on same-origin requests, which are unrestricted by default.
Can browser privacy features affect CORS behavior?
In some cases yes — certain privacy-focused browser features can interact with cross-origin request handling in ways worth testing explicitly.
Check CORS Configuration
Run an HTTP header analysis to see the CORS headers configured for any URL.
Launch Tool →