Medium severity · Next.js

CORS allows all origins on Next.js

Your API responds with `Access-Control-Allow-Origin: *`, which allows any website to call your endpoints. For public APIs that do not handle authentication, this is intentional and fine. For any endpoint that relies on session cookies or auth tokens, it is a bug. Fix it by setting the header to a specific allowed origin, or a narrow allowlist — and remove `Access-Control-Allow-Credentials: true` if you do not actually use credentialed requests.

The fix for Next.js

Next.js Route Handlers

Read the request Origin header; reflect it if it is in your allowlist.

const ALLOWED = ['https://app.example.com', 'https://example.com'];

export async function GET(req: Request) {
  const origin = req.headers.get('origin');
  const headers = new Headers({ 'content-type': 'application/json' });
  if (origin && ALLOWED.includes(origin)) {
    headers.set('Access-Control-Allow-Origin', origin);
    headers.set('Vary', 'Origin');
  }
  return new Response(JSON.stringify({ ok: true }), { headers });
}

Why it matters

CORS is defense against cross-origin attacks. A wildcard means any malicious site can call your API from a user's browser. If you set both `Allow-Origin: *` and `Allow-Credentials: true` (which browsers reject, but proxies sometimes rewrite), you have a serious CSRF-equivalent.

Confirm the fix worked

Scan your Next.js site to confirm this finding is gone.

AI prompt

Apply across your codebase

Paste this into Cursor, Lovable, Bolt, v0, or Claude Code.

My API responds with `Access-Control-Allow-Origin: *`. For each of my API endpoints, tell me whether it is meant to be public (in which case the wildcard is fine) or meant to serve authenticated user data (in which case it is a bug). For the authenticated ones, implement an allowlist of my known frontend origins and reflect the Origin header when it matches. Add `Vary: Origin` for correct caching.

FAQ

Frequently asked questions

Can I just use credentials: "include" with wildcard?
No — browsers reject that combination. If your fetch uses `credentials: "include"`, you must set a specific origin, not *.
What about preflight (OPTIONS) requests?
Preflight responses also need the allow-origin header, plus `Access-Control-Allow-Methods` and `Access-Control-Allow-Headers`. Handle OPTIONS explicitly in your route handler.