HIGH Express · Fastify · Next.js route handlers

CORS set to allow everything, with credentials on

What you'd see: You have app.use(cors()) or an origin reflected from the request header, plus cookie-based sessions.

§ 01 — What's actually happening

The browser blocks cross-site reads by default; CORS is how you selectively unblock them. Allowing every origin while also allowing credentials tells the browser that any website may make authenticated requests to your API using your users' cookies and read the answer. A page a user visits in another tab can quietly act as them.

Why an AI tool writes it this way

CORS errors are among the most frustrating things to debug, and the fastest fix that makes them disappear is to allow everything. It works instantly, and the browser stops complaining — so there is no signal that anything is wrong.

What it costs you

A malicious or merely compromised site can read your users' data and perform actions as them, with no phishing and no stolen password. It is the classic setup for cross-site request forgery against a JSON API.

§ 02 — Before & after

Any website can call your API as your user

Illustrative code, written for this page — never a client's project.

AI-generated

  • Every origin allowed, including ones that do not exist yet
  • Credentials permitted, so session cookies ride along
  • Any method accepted, including DELETE
app.use(cors({ origin: (req, cb) => cb(null, true), // reflects whatever asked credentials: true // ...and sends the cookies }));

Human-reviewed

  • Explicit allowlist of origins you control
  • Unknown origins rejected outright
  • Only the methods and headers you actually use
const ALLOWED = new Set([ 'https://fixmyvibecodes.com', 'https://app.fixmyvibecodes.com', ...(process.env.NODE_ENV !== 'production' ? ['http://localhost:5173'] : []) ]); app.use(cors({ origin: (origin, cb) => { if (!origin) return cb(null, true); // curl, mobile apps if (ALLOWED.has(origin)) return cb(null, true); cb(new Error('Origin not allowed')); }, credentials: true, methods: ['GET', 'POST', 'PATCH', 'DELETE'], allowedHeaders: ['Content-Type', 'Authorization'], maxAge: 86400 }));

§ 03 — Check your own

How to tell in two minutes

You don't need us to run these. If any of them come back the wrong way, you have this problem.

  1. Run curl -I -H "Origin: https://evil.example" https://yourapi.com/api/me. If Access-Control-Allow-Origin comes back as https://evil.example, every origin is allowed.
  2. Check whether Access-Control-Allow-Credentials: true is also present. The two together are what makes this exploitable.
  3. A literal * wildcard is safer than reflection — browsers refuse to send credentials with it. Reflection is the dangerous pattern.
  4. Set your session cookies to SameSite=Lax or Strict as a second layer.

Found it in your project? Fixing this one properly usually takes an engineer under an hour. Finding the other nine takes longer — which is what the free health check is for.

Get my free health check

Find out where you actually stand.

Free. No obligation. Reviewed by experienced engineers.

Get my free health check