Stop 2 of 42 · The Front Door · CORS

Handing statements to anyone’s messenger

When Alice visits another building, that building can send a messenger to the bank carrying her badge. The teller decides which buildings’ messengers get a statement. If the teller says “anyone’s,” Mallory’s shop gets Alice’s statement the moment she walks in.

Severity Medium–CriticalCategory Auth WeaknessThe Front DoorSources checked 25 Oct 2026

Watch it happen

Play it as

Alice visits Mallory’s shop. Mallory’s messenger takes Alice’s badge to the bank, and the teller hands the statement to any messenger.

Arrival

Alice is logged in to the bank, so her browser holds a badge. She walks in through the front door.

1 / 5

In bank terms and app terms

In the bankIn your app
Another building’s messengerJavaScript on a different website calling your API
Badge pinned on automaticallyThe browser sending the user’s cookies along (cross-site only for SameSite=None cookies)
The guest listAn allowlist of origins in Access-Control-Allow-Origin
“Any building is fine”Using *, or copying the request’s Origin header back (the dangerous one when cookies are involved)

Are you exposed?

You might be exposed if…
  • Your API sets Access-Control-Allow-Origin: *, or copies the incoming Origin header straight back.
  • You turned on CORS for “everything” to make a local-dev error go away and never narrowed it.
  • Your API relies on cookies, and also allows null or any subdomain as an origin.
What to do about it
  1. Keep a list of exact origins you trust (your own app and admin site) and only echo an origin if it is on the list.
  2. Browsers refuse a wildcard together with cookies, so don’t “fix” that error by echoing any origin back. Never allow the null origin.
  3. For public data that needs no login, * is fine. For anything tied to a user, use the allowlist.

Track these in your to-do list →

What it looks like in code

// BAD: Wildcard CORS (browsers refuse "*" together with credentials, so the real exploit is reflecting the Origin header)
response.headers.set("Access-Control-Allow-Origin", "*")
response.headers.set("Access-Control-Allow-Credentials", "true")

// BAD: Reflecting the Origin header without validation
const origin = request.headers.get("Origin")
response.headers.set("Access-Control-Allow-Origin", origin)

Ask your AI tool to fix it

Paste this into Cursor, Claude, Lovable, Bolt or whatever you build with.

Prompt
Audit the CORS configuration of this app. Replace any Access-Control-Allow-Origin: * or code that reflects the request Origin with an allowlist of exact origins read from an environment variable. Only send Access-Control-Allow-Credentials: true for origins on that list, never allow the "null" origin, and add Vary: Origin. Keep local development working with a localhost entry in the dev env only.

Where this comes from

The facts, figures and fixes on this page were checked against these sources on 25 Oct 2026. They are linked so you can check for yourself.

Spot a mistake or something out of date? Report a correction · How these guides are made and checked

Go deeper in isitsecure

The free, open-source scanner checks for most of the problems in these guides.