Loading
GGX_LABS
KNOWLEDGE MODULE

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.

Insight: CORS is enforced entirely by the browser, not the server — a server without CORS headers still processes the request, but the browser blocks the response from reaching the calling script.

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
Limitation: A misconfigured preflight response — wrong methods or headers allowed — will silently block the actual request even if the main endpoint itself is configured correctly.

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
Insight: An explicit, maintained allowlist of trusted origins is more work than a wildcard, but it's the only approach that scales safely with credentialed requests.

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 →
END OF MODULE