CORS & Security Boundaries
Key Learning Objectives
Differentiate the Same-Origin Policy (SOP) from Cross-Origin Resource Sharing (CORS).
Understand why CORS is a browser sandbox enforcement policy, NOT server-side authentication or authorization.
Master the preflight OPTIONS request handshake, including Access-Control-Request-* headers.
Know the strict credentials rule: why wildcard Access-Control-Allow-Origin (*) fails when credentials: 'include'.
Identify default CORS-safelisted response headers vs custom headers requiring Access-Control-Expose-Headers.
The Interview Problem
What is logged to the console when the following function evaluates CORS response headers and credentials policies across four different cross-origin request configurations?
1function evaluateCorsPolicy({ requestOrigin, allowedOrigin, allowsCredentials, requestCredentials, exposedHeaders, headerToRead }) {2 const originMatches = allowedOrigin === '*' || allowedOrigin === requestOrigin;3 const credentialsValid = !requestCredentials || (allowsCredentials && allowedOrigin !== '*');4 const allowed = originMatches && credentialsValid;56 if (!allowed) {7 return 'CORS_ERROR';8 }910 const defaultExposed = new Set(['cache-control', 'content-language', 'content-type', 'expires', 'last-modified', 'pragma']);11 const isExposed = defaultExposed.has(headerToRead.toLowerCase()) || exposedHeaders.map(h => h.toLowerCase()).includes(headerToRead.toLowerCase());1213 return isExposed ? 'HEADER_READ' : 'HEADER_BLOCKED';14}1516const req1 = evaluateCorsPolicy({17 requestOrigin: 'https://app.faangprep.com',18 allowedOrigin: '*',19 allowsCredentials: true,20 requestCredentials: true,21 exposedHeaders: ['X-Custom-Token'],22 headerToRead: 'X-Custom-Token'23});2425const req2 = evaluateCorsPolicy({26 requestOrigin: 'https://app.faangprep.com',27 allowedOrigin: 'https://app.faangprep.com',28 allowsCredentials: true,29 requestCredentials: true,30 exposedHeaders: ['X-Custom-Token'],31 headerToRead: 'X-Custom-Token'32});3334const req3 = evaluateCorsPolicy({35 requestOrigin: 'https://app.faangprep.com',36 allowedOrigin: 'https://app.faangprep.com',37 allowsCredentials: false,38 requestCredentials: false,39 exposedHeaders: [],40 headerToRead: 'X-Secret-Rate-Limit'41});4243const req4 = evaluateCorsPolicy({44 requestOrigin: 'https://app.faangprep.com',45 allowedOrigin: 'https://app.faangprep.com',46 allowsCredentials: false,47 requestCredentials: false,48 exposedHeaders: [],49 headerToRead: 'content-type'50});5152console.log(req1, req2, req3, req4);
Predict Console Output
Select the option that matches what standard ECMAScript prints to the console:
CORS_ERROR HEADER_READ HEADER_BLOCKED HEADER_READ
HEADER_READ HEADER_READ HEADER_BLOCKED HEADER_READ
CORS_ERROR HEADER_READ HEADER_READ HEADER_READ
CORS_ERROR CORS_ERROR HEADER_BLOCKED HEADER_BLOCKED
V8 Engine Execution Trace
Step 1 of 6 (Line 1)Declares evaluateCorsPolicy function modeling browser CORS evaluation algorithm.
Deep Technical Breakdown
The Fundamentals of Cross-Origin Resource Sharing (CORS)
CORS is one of the most frequently tested security mechanisms in senior frontend and full-stack interviews:
1. CORS is a Browser Policy, NOT Server Security
- The browser's Same-Origin Policy (SOP) prevents web applications on
https://site-a.comfrom reading data loaded fromhttps://api-b.comunlessapi-b.comexplicitly grants permission via CORS headers. - Critical Interview Fact: Non-browser clients (such as
curl, Postman, Python scripts, or server-to-server microservices) completely ignore CORS headers. A server that lacks CORS protections will still receive the HTTP request, execute database writes, and return data to non-browser attackers. - CORS is NOT authentication or authorization: Never use CORS headers in place of session cookies, JWTs, or API keys.
2. Simple Requests vs Preflight (OPTIONS) Requests
A request is Simple (no preflight sent) if:
- HTTP method is
GET,HEAD, orPOST. - Headers only include:
Accept,Accept-Language,Content-Language, orContent-Typewith values limited toapplication/x-www-form-urlencoded,multipart/form-data, ortext/plain.
Any request with Content-Type: application/json or custom headers triggers an automatic preflight OPTIONS request:
- Browser sends:
Origin,Access-Control-Request-Method,Access-Control-Request-Headers. - Server must respond with
200or204and headers:Access-Control-Allow-Origin,Access-Control-Allow-Methods,Access-Control-Allow-Headers, and optionallyAccess-Control-Max-Age(caching preflights).
3. The Credentials Trap (credentials: 'include')
When an application sends cross-origin cookies or auth headers:
- Server must return
Access-Control-Allow-Credentials: true. - Server CANNOT return wildcard
*forAccess-Control-Allow-Origin. It must return the exact matching requesting origin (e.g.,https://app.faangprep.com).
4. Response Header Safelist
By default, JavaScript fetch can only read: Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, and Pragma. Any other header requires Access-Control-Expose-Headers: X-Custom-Header.
Common Traps & Mistakes
Believing that CORS protects servers from malicious requests. It only prevents the client browser from exposing the response to JavaScript.
Attempting to pair `Access-Control-Allow-Origin: *` with `credentials: 'include'`. Browsers reject this combination with a CORS failure.
Assuming preflight requests can be stopped in JavaScript code. The browser network stack automatically initiates preflights when requests are not 'simple'.
Forgetting to set `Access-Control-Expose-Headers` for custom backend telemetry, pagination, or rate-limiting headers.
FAANG Follow-Up Probes
Probe #1
How does Access-Control-Max-Age improve network performance for high-frequency REST or GraphQL API calls?
Probe #2
Why does a server-side Reverse Proxy (e.g. Nginx, Next.js rewrites) completely eliminate CORS issues in production?
Probe #3
How does the Sec-Fetch-Site and Sec-Fetch-Mode metadata header family enhance cross-origin request security beyond CORS?
