Misconfigured CORS Preflight Cache Security Risks
Cross-Origin Resource Sharing (CORS) preflight requests protect web
applications by validating cross-origin permissions before complex HTTP
requests are executed. To optimize network performance, servers use the
Access-Control-Max-Age response header to cache these
preflight checks in the browser. However, setting this directive
improperly introduces serious security vulnerabilities, including
prolonged windows of exploitation, delayed mitigation of policy
blunders, and risks related to intermediary cache poisoning.
The Mechanics of Preflight Caching
When a browser makes a cross-origin request involving non-simple
methods (like PUT or DELETE) or custom
headers, it first dispatches an OPTIONS preflight request.
The server replies with CORS authorization headers along with
Access-Control-Max-Age, which indicates in seconds how long
the browser may cache the authorization without sending another
preflight check.
While caching reduces network overhead, errors in these cache configurations amplify standard CORS misconfigurations into persistent security threats.
Delayed Revocation of Overly Permissive Policies
If a developer accidentally misconfigures a server to allow an
unauthorized or overly broad origin (such as echoing back any incoming
Origin header or trusting an unverified subdomain) and
couples this with a large Access-Control-Max-Age value, the
vulnerability persists client-side. Even after the backend configuration
is corrected and deployed, existing clients with cached preflight
entries will continue to bypass the updated CORS checks until the
client-side timer expires. This creates an unpatchable window of
vulnerability where attackers can still execute unauthorized
cross-origin requests from the compromised origin against affected user
sessions.
Prolonged Exploitation of Ephemeral Domain Takeovers
Subdomain takeovers and temporary domain lapses are common attack
vectors. If an API trusts *.example.com and an attacker
temporarily claims an abandoned subdomain, a high
Access-Control-Max-Age allows the attacker to lock in valid
preflight permissions on a victim's browser. Even after the organization
reclaims or tears down the rogue subdomain, the victim’s browser retains
the preflight validation, enabling continued exploitation until the
cache naturally clears.
Cache Poisoning and Header Desynchronization
When preflight requests interact with intermediary caches, content delivery networks (CDNs), or reverse proxies, misconfigured caching rules can lead to cache poisoning:
- Missing
Vary: OriginHeader: If a server dynamically generates theAccess-Control-Allow-Originheader based on the incoming request but fails to includeVary: Origin, a shared proxy may cache a permissive response intended for an attacker and serve it to legitimate users, or vice versa. - Mismatched Cache TTLs: If the CDN’s cache TTL
differs from the browser's
Access-Control-Max-Age, preflight states become desynchronized. An attacker can prime the intermediary cache with malicious CORS headers, effectively altering the API's security boundaries for all users routed through that proxy.
Bypassing Routine Origin Validation
APIs that handle dynamic authentication states or rate limiting at the preflight level lose control when caching is excessive. Because cached preflight requests bypass the server entirely, real-time security logic—such as IP blocklists, origin revocation, or anomaly detection—is not triggered prior to the execution of the actual cross-origin request.
Mitigation and Best Practices
To mitigate the risks associated with CORS preflight caching:
- Limit Cache Lifespans: Avoid setting excessive
Access-Control-Max-Agevalues. Modern browsers enforce their own caps (for example, Chromium caps this value at 7200 seconds, or two hours), but keeping values between 10 and 30 minutes minimizes exposure without severely degrading performance. - Always Use
Vary: Origin: Ensure web servers and edge caches properly separate preflight responses based on the requesting origin. - Never Pair Dynamic Origins with Long Caches: If the
server dynamically reflects the
Originheader or applies dynamic validation rules, keep theAccess-Control-Max-Agelow or omit it entirely to force real-time evaluation.