Advanced CORS Patterns for CDN-Proxied API Architectures

· David Park · 11 min read

Cross-Origin Resource Sharing controls which web origins can access your API from a browser. At a single-origin server, CORS is a set of response headers — straightforward to configure. But when a CDN sits between the browser and the origin, CORS becomes an architectural problem. The CDN's caching layer interacts with CORS headers in ways that break cross-origin access, and the distributed nature of CDN edge nodes means CORS configuration must be consistent across hundreds of PoPs while remaining dynamic enough to accommodate multiple legitimate origins.

The Fundamental CORS-CDN Conflict

CORS responses include the Access-Control-Allow-Origin header, which names the specific origin allowed to access the resource. When a CDN caches a response, it caches the entire response including this header. If the first request comes from https://app.example.com, the CDN caches the response with Access-Control-Allow-Origin: https://app.example.com. When a second request arrives from https://admin.example.com, the CDN serves the cached response — but the browser sees an Access-Control-Allow-Origin value that does not match its origin and blocks the response.

This is the Vary header problem. The HTTP Vary header tells caches (including CDNs) which request headers affect the response. A CORS response must include Vary: Origin to tell the CDN that responses vary by the Origin request header. This creates separate cache entries per origin, solving the correctness problem but reducing cache hit rates — each origin gets its own cached copy of every resource.

Three Architectural Approaches

CDN architects handle the CORS-caching conflict with three patterns, each suited to different traffic profiles.

Vary-based splitting: Set Vary: Origin on all CORS responses. The CDN creates per-origin cache slots. This is the simplest correct approach but fragments the cache. For APIs serving 5–10 origins, the cache fragmentation is negligible. For APIs serving hundreds of origins (an API marketplace), cache hit rates may drop below useful levels.

Edge-layer CORS injection: The origin returns responses without CORS headers. The CDN caches the header-free response. An edge worker adds CORS headers per-request based on the incoming Origin header. This maximizes cache hit rates (one cached copy per resource regardless of origin count) and centralizes CORS logic at the edge. The tradeoff is complexity — the edge worker must implement the full CORS specification including preflight handling.

Cache bypass for CORS: CORS-sensitive responses bypass the CDN cache entirely, flowing through the edge to the origin on every request. This is correct but eliminates CDN benefits. It is a reasonable approach only for low-volume APIs where cache hit rates are already low.

Three CORS-CDN Architecture Approaches Vary-Based Splitting Separate cache per origin + Simple, correct - Cache fragmentation Best: < 10 origins Edge CORS Injection Headers added at edge + Optimal cache efficiency - Implementation complexity Best: many origins Cache Bypass No caching for CORS + Trivially correct - No CDN benefit Best: low-volume APIs Recommended: Edge CORS Injection Maximum cache efficiency with centralized CORS control
Figure 1: Three approaches to resolving the CORS-CDN caching conflict — edge CORS injection provides the best balance for multi-origin APIs.

Dynamic Origin Whitelisting at CDN Edge

Static CORS configurations — a hardcoded list of allowed origins — do not scale. Production APIs add origins as new frontends, mobile web views, partner integrations, and staging environments come online. Redeploying the CDN edge worker for every origin change is operationally expensive and introduces deployment risk.

Performance Comparison: Edge vs Origin Processing
Metric Edge Processing Origin Processing Improvement
Latency (p50)8–15 ms120–300 ms15–20x faster
Cache Hit Ratio85–95%N/AReduces origin load
TLS Handshake1–5 ms (nearby PoP)50–150 ms10–30x faster
Bandwidth Cost$0.01–0.04/GB$0.05–0.12/GB3–5x cheaper
Availability99.99% (multi-PoP)99.9% (single DC)10x fewer outages

KV-Based Origin Lists

The edge worker stores the origin whitelist in edge KV. The whitelist entry contains exact origins (https://app.example.com), wildcard patterns (*.example.com), and optional metadata (which CORS methods and headers each origin is allowed to use). The edge worker reads the whitelist on each request, checks the incoming Origin header against the list, and sets Access-Control-Allow-Origin to the matching origin value.

To avoid a KV read on every request, the edge worker caches the whitelist in memory with a 60–300 second TTL. This means origin additions take effect within the cache TTL without redeployment. For emergency origin removal (a compromised origin), the cache TTL is the maximum delay before the removal takes effect — acceptable for most security scenarios.

Wildcard Subdomain Matching

Many CDN-proxied APIs need to allow all subdomains of a base domain: *.example.com covers app.example.com, staging.example.com, feature-branch-123.example.com, and any future subdomain. The edge worker implements wildcard matching by extracting the subdomain from the incoming origin and checking whether the base domain (everything after the first dot) matches a wildcard entry.

Wildcard subdomain matching must be implemented carefully to avoid security bypasses. The pattern *.example.com must match sub.example.com but must not match example.com (the bare domain) or evil-example.com (a different domain with a matching suffix). The edge worker should parse the origin URL, extract the hostname, split on dots, and compare segments — never use simple string suffix matching, which is vulnerable to subdomain confusion attacks.

Preflight Optimization at CDN Edge

CORS preflight requests (HTTP OPTIONS) are the primary performance cost of cross-origin APIs. Every "non-simple" cross-origin request — one that uses methods other than GET/HEAD/POST, custom headers, or content types other than form-encoded, multipart, or plain text — triggers a preflight. The browser sends an OPTIONS request before the actual request, adding a full round-trip to the API call.

Edge Preflight Response

CDN edge workers can respond to preflight requests entirely at the edge, without forwarding to the origin. The edge worker detects OPTIONS requests with Access-Control-Request-Method headers, validates the requesting origin against the whitelist, and returns the appropriate CORS preflight headers: Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers, and Access-Control-Max-Age.

Edge-terminated preflights eliminate origin round-trips, reducing preflight latency from 100–500ms (origin RTT) to 1–5ms (edge processing). For APIs that receive thousands of preflight requests per second, this offloads significant traffic from the origin server.

Preflight Cache Duration

The Access-Control-Max-Age header controls how long the browser caches preflight results. Setting it to 86400 (24 hours) means each unique origin/method/header combination triggers at most one preflight per day per browser. Higher values reduce preflight traffic but delay the effect of CORS policy changes — if you add a new allowed method, browsers with cached preflights will not see it until the cache expires.

For stable production APIs where CORS policy changes are rare, 86400 to 604800 (7 days) is appropriate. For APIs in active development where CORS policy changes frequently, 3600 (1 hour) provides a balance between performance and responsiveness to changes. Note that browsers cap Access-Control-Max-Age — Chrome limits it to 7200 seconds (2 hours) and Firefox to 86400 seconds (24 hours), regardless of the header value.

Credentialed Cross-Origin Requests

When a cross-origin request includes credentials (cookies, Authorization header, or TLS client certificates), CORS imposes additional restrictions. The response must include Access-Control-Allow-Credentials: true and Access-Control-Allow-Origin must be set to the exact requesting origin (not *). The CDN edge worker must enforce both requirements for credentialed requests.

Credential Detection at Edge

The edge worker detects credentialed requests by checking for the presence of Cookie headers, Authorization headers, or client certificates in the TLS handshake. For credentialed requests, the edge worker sets Access-Control-Allow-Credentials: true alongside the origin-specific Access-Control-Allow-Origin header. The edge must never respond with Access-Control-Allow-Origin: * when Access-Control-Allow-Credentials: true is set — browsers reject this combination as a security violation.

Cookie Scope and SameSite Interaction

Cross-origin credentialed requests that rely on cookies face additional constraints from the SameSite cookie attribute. Cookies set with SameSite=Strict are never sent on cross-origin requests. Cookies set with SameSite=Lax are sent only on top-level navigations, not on cross-origin fetch/XHR calls. Only cookies with SameSite=None; Secure are sent on cross-origin requests.

This means the CDN gateway must set session cookies with SameSite=None; Secure if they need to be available for cross-origin API calls from frontend applications on different domains. The Secure attribute is mandatory when SameSite=None is set, restricting these cookies to HTTPS connections — which is a given for CDN-proxied domains using TLS termination.

Credentialed CORS Request Flow at CDN Edge Browser Origin: app.com Cookie: session=... fetch() CDN Edge Worker 1. Validate Origin ∈ whitelist 2. Detect credentials 3. Set ACAO + ACAC: true Origin API Process request Return data CORS Response Headers (set by edge worker, not cached with response) Access-Control-Allow-Origin: https://app.com | Access-Control-Allow-Credentials: true | Vary: Origin NEVER: Access-Control-Allow-Origin: * with Credentials: true (browser rejects this)
Figure 2: Credentialed CORS request handling at CDN edge — the edge worker adds CORS headers per-request rather than caching them with the response.

CORS Security Pitfalls at CDN Edge

CORS misconfigurations at CDN edge are especially dangerous because they affect all traffic through the CDN, not just one origin server. Several common pitfalls appear in CDN CORS implementations.

Origin Reflection Without Validation

The most dangerous CORS misconfiguration is reflecting the incoming Origin header directly into Access-Control-Allow-Origin without checking it against a whitelist. This effectively allows any website to make cross-origin requests to the API, including malicious sites that can exfiltrate data using the victim's credentials. CDN edge workers must always validate the origin before reflecting it.

Null Origin Acceptance

Some CORS implementations accept Origin: null (which browsers send for requests from local files, data URIs, and sandboxed iframes). Allowing null as a valid origin opens the API to attacks from sandboxed iframes, which an attacker can embed on any website. The CDN edge worker should never include null in its origin whitelist.

Incomplete Preflight Validation

Edge workers that respond to OPTIONS preflights without checking the requesting origin create a timing gap: the preflight succeeds (telling the browser the request is allowed), but the actual request may fail CORS checks at the origin. This inconsistency confuses developers and can mask real CORS issues. The edge worker should apply the same origin validation to preflight requests as it does to actual requests.

Subdomain Confusion

Wildcard subdomain patterns like *.example.com must not match attacker.com.example.com (which is a valid subdomain but likely not intended) or examplexcom (through improper string matching). The edge worker's origin matching must parse the origin URL correctly, splitting the hostname into segments and matching from the right (top-level domain first) rather than using naive string operations.

Testing CORS at CDN Edge

CORS issues are notoriously difficult to debug because they only manifest in browsers making cross-origin requests. CDN monitoring should include CORS-specific checks: synthetic tests that make cross-origin requests from multiple origins and verify the response headers, monitoring for 403 or missing CORS header responses on legitimate cross-origin traffic, and alerts when the origin whitelist is modified (to catch accidental deletions).

Edge log analysis should track the Origin header on all requests, flagging origins that receive CORS failures (potential whitelist gaps) and origins that receive CORS success but are not in the whitelist (potential security issues). The logs should also track preflight request volume and cache hit rates to identify opportunities for Access-Control-Max-Age tuning.

For development and staging environments, CDN edge workers should support a CORS debug mode that adds detailed response headers explaining why a CORS check succeeded or failed: which whitelist entry matched, whether the request was credentialed, and which preflight cache was used. The debug headers should be gated behind a debug token to prevent information leakage in production.

External References

References & Standards: RFC 7234 · OWASP CDN Security