Course / 09 Web security / Lesson 18 of 28

CORS

Estimated time: 16 min reading · 12 min activity

A page sometimes needs to read a response from another origin. An origin combines scheme, host and port. Cross-Origin Resource Sharing, or CORS, is the browser mechanism through which a server permits certain cross-origin access. It is separate from authenticating a caller or authorizing an action.

For some requests, the browser first sends an OPTIONS preflight asking whether the intended origin, method and headers are permitted. Access-Control-Allow-Origin names a permitted origin in the response. Credentialed response access has additional requirements; an allow-origin header does not grant a user permission to alter records.

Before you begin

Estimated time
16 min reading, 12 min activity. Setup and optional practice may take longer.
Where you work
Use the fictional page source, requests and policy models printed here in any current desktop or mobile browser. No server, login, framed account page or socket connection is required.
Without a lab
Read each source fragment or model and predict its result in notes. Identify the boundary, the supporting fact and one limit, then compare with the activity rubric. This does not reproduce a browser exchange. Reading works without JavaScript. Checking requires JavaScript and a secure context; saving additionally requires usable browser storage.

After this lesson you can:

  • Read the requested origin and the allow-origin value as different names.
  • Say that a shell client does not consult the browser policy.
  • Name the side that still has to authorize the change.

01Example

Worked policy: notes is listed and other is not. The activity transcript is the OPTIONS model.

Listed origin: https://notes.club.invalid
Unlisted origin: https://other.club.invalid
Allow-origin for a listed origin is that origin, not a star.

02A browser rule is not a permission

The synthetic request comes from other.club.invalid while the response names notes.club.invalid. Those are different hosts and therefore different origins. Listing PATCH in allowed methods cannot fix the origin mismatch. Under this model, the browser does not proceed with the requested cross-origin operation after that failed preflight.

The trust decision here is whether a browser may expose the cross-origin response and proceed with a preflighted call. Enforce a narrow CORS policy where cross-origin browser access is intended, while still checking identity and resource permission on the server. Some cross-origin requests do not need preflight, and a non-browser client does not enforce browser CORS, so CORS cannot be the application's general access control.

Read a synthetic preflight as a browser rule, and keep the server's permission check on the server.Model. A teaching model drawn by hand. It shows the idea, not real tool output.

Read the full explanation below.

listed-originpermission
FieldListed originUnlisted origin
Request originhttps://notes.club.invalidhttps://other.club.invalid
Explicitly listedYesNo
Allow-origin response rolehttps://notes.club.invalidNo allowed origin supplied for this host
Server record access ruleSeparate server policySeparate server policy
Exact origin differs

The listed origin receives its exact origin value, not a star.

The listed origin receives its exact origin value, not a star.

Follow the explanation

  1. The listed origin receives its exact origin value, not a star.
  2. A browser read rule does not decide the server’s access decision for either origin.
Read every state and value

1. The listed origin receives its exact origin value, not a star.

Selected Comparison
listed-origin
Highlighted Field
Request origin · Listed origin · Allow-origin response role

2. A browser read rule does not decide the server’s access decision for either origin.

Selected Comparison
permission
Highlighted Field
permission
CORS governs browser cross-origin access; it does not replace the server's resource permission check.

03Read the transcript

Read the evidence before comparing with the activity rubric. Send nothing.

Response policy model. No browser request was sent.

Origin https://notes.club.invalid is listed.
Origin https://other.club.invalid is not listed.
The card's allow-origin value for a listed origin is that origin, not a star.
This policy does not permit credentialed cross-origin response access for an unlisted origin. Cookie sending follows separate browser rules.

A shell client does not consult this browser policy.
The server must independently authorize an action regardless of which client sends it.

Download the origin policy

Synthetic preflight model. Not a captured browser exchange.

Request
OPTIONS /notes/7
Origin: https://other.club.invalid
Access-Control-Request-Method: PATCH

Response
204
Access-Control-Allow-Origin: https://notes.club.invalid
Access-Control-Allow-Methods: GET, PATCH

The requested origin is other. The allow-origin value is notes.
The model does not treat those as the same origin.
The server's permission check is a separate decision and is not shown on this transcript.

Download the synthetic preflight

  1. Write the Origin on the request and the allow-origin value on the response.
  2. Say whether the model treats them as the same origin.
  3. Check: the request origin is other and the allow-origin value is notes. They are not the same. A shell client is outside this browser policy.
  4. Stop. Do not send the OPTIONS request.

04Optional challenge

Say what the transcript shows and what it does not show. The rubric is: it shows an origin mismatch in a model, and it does not show the server's permission decision. About ten minutes.

05Fresh cases for the checks

Use these fictional cases for the checks below. They have different inputs from the worked examples. Read them here or make notes; no installation or external service is needed.

Origin case A: fresh synthetic preflightsOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.

Each proposed browser request uses PATCH. All response method lists include PATCH.
P request Origin https://reader.lab.invalid; response allow-origin https://reader.lab.invalid.
Q request Origin https://archive.lab.invalid; response allow-origin https://reader.lab.invalid.
R request Origin http://reader.lab.invalid; response allow-origin https://reader.lab.invalid.
Compare full origins including scheme. No exchange occurred; server action permissions are not shown.

Origin case B: independent client comparisonOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.

Browser client and shell client propose the same state-changing request.
Response policy allows only https://reader.lab.invalid.
Caller permission to change the selected note has not been established.
The shell client does not enforce browser CORS.

06Explain your evidence

Optional written self-check: explain one decision using the supplied case. No tool run is required.

Check your explanation: compare complete requested and allowed origins; separate method matching from origin matching; distinguish browser enforcement from shell behavior; name the missing server resource/action check.

07Common mistakes

If you treat other and notes as one site because both end in club.invalid, you skipped the host. The model says they differ.

If you treat the allow-methods list as permission for a shell client, the transcript is a browser model.

If you call this a captured browser exchange, the file says it is synthetic.

References

  • RFC 6454: The Web Origin Concept

    An origin is scheme, host, and port. A browser's reading limit is not a server authorization check, and curl is not bound by it. The transcript is synthetic.

  • PortSwigger: CORS

    Explains this mechanism, its impact and defenses. Required reasoning uses the original evidence printed on this page.