CORS & Security Boundaries

Hard100% Free~30 mins#cors#same-origin-policy#preflight#security#http-headers#browser-apis#network
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;
5
6 if (!allowed) {
7 return 'CORS_ERROR';
8 }
9
10 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());
12
13 return isExposed ? 'HEADER_READ' : 'HEADER_BLOCKED';
14}
15
16const 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});
24
25const 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});
33
34const 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});
42
43const 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});
51
52console.log(req1, req2, req3, req4);
Predict Console Output
Interactive Challenge

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.

Call Stack (Top = Active)
Global Execution Context
Lexical Scope / Bindings
evaluateCorsPolicy:function
Console Stream
> [empty]

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.com from reading data loaded from https://api-b.com unless api-b.com explicitly 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, or POST.
  • Headers only include: Accept, Accept-Language, Content-Language, or Content-Type with values limited to application/x-www-form-urlencoded, multipart/form-data, or text/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 200 or 204 and headers: Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers, and optionally Access-Control-Max-Age (caching preflights).

3. The Credentials Trap (credentials: 'include')

When an application sends cross-origin cookies or auth headers:

  1. Server must return Access-Control-Allow-Credentials: true.
  2. Server CANNOT return wildcard * for Access-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?