SecurityBlog Post

CORS and Cookie Authentication: Wildcards, Origin Reflection, and Real Risks

Browsers block credentialed reads with a wildcard CORS origin. Reflecting an untrusted origin while allowing credentials is a different configuration that can expose private responses.

By Abhay Mittal

3 min read
CORS and Cookie Authentication: Wildcards, Origin Reflection, and Real Risks
Is your AI-built app exposed? Get a professional vibe coding audit and ship to production with confidence.

Cookie-based APIs need explicit rules for which browser origins may read their responses. The dangerous configuration is accepting an attacker's origin while allowing credentials.

When fixing a local CORS error, review the resulting configuration before deploying it. A change that makes development easier may authorize more origins than your application needs.

MDN documents that browsers block credentialed response reads when the allowed origin is *. A wildcard plus credentials: true is therefore not, by itself, proof that another site can read authenticated data.

Here's what the broken version looks like:

app.use(cors({
  origin: '*',
  credentials: true,
}));

The middleware may emit those headers without throwing an error, but the browser will reject a credentialed read. Replacing the wildcard with unrestricted origin reflection creates a different risk:

app.use(cors({
  origin: (origin, callback) => callback(null, true),
  credentials: true,
}));

An attacker-controlled page can request your API with credentials: 'include'. If cookie settings and browser policies permit the session cookie to be sent, reflecting that page's origin with credential support can expose the response. Cookie transmission depends on factors including SameSite, the request's credentials mode, and third-party cookie restrictions; it is not automatic for every cross-site request. See MDN's CORS guide.

Here's the fix. List the exact origins your app runs on, and nothing else:

const allowedOrigins = [
  'https://yourapp.com',
  'https://app.yourapp.com',
];

app.use(cors({
  origin: (origin, callback) => {
    if (!origin || allowedOrigins.includes(origin)) {
      return callback(null, true);
    }
    callback(new Error('Not allowed by CORS'));
  },
  credentials: true,
}));

For browser origins outside the list, this middleware returns an error. The example allows requests without an Origin header; those still require authentication and authorization. CORS is a browser response-reading policy, not a replacement for server-side access controls.

Keep the production allowlist specific and review who controls every allowed origin. Also protect state-changing cookie-authenticated requests against CSRF. A blocked response does not prove that a request had no server-side effect; OWASP explains this distinction in its CSRF guidance. Changing authentication mechanisms requires a separate review of token storage and exposure.

To test an application you control, use a separate origin and a test account. Inspect the allowed-origin and allowed-credentials headers, verify whether cookies are sent, and check whether JavaScript can actually read a private response. Confirm that unapproved origins cannot read protected data and that state-changing routes have independent CSRF defenses. A wildcard beside a Set-Cookie header alone does not confirm an exploitable data leak.

If you want someone else to check this for you, book an audit call. We'll discuss your app's CORS setup and auth flow, scope the review, and provide a fixed-price quote.

VibeAudits audits apps built with Cursor, Lovable, Bolt, Claude Code, Replit, and other AI tools.

Keep reviewing your app

Practical checks for the parts of an AI-built app that handle real users and money.

Need a second pair of eyes? Explore our code audit services, scope and pricing, and client case studies.

VibeAudits

Security Experts

Worried your vibe-coded app has issues like this?

Bring us in as your Partner and we audit the code, fix what we find and take it to launch (from $1,000). Building it yourself? A Mentor plan puts a senior engineer on call for $29 a month.