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

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.
Test API access control
Use two test accounts to check whether one user can access another user's data.
Vibe-coded app security checklist
Work through 25 checks before accepting real users, payments, and private data.
How to review vibe-coded apps
Plan a review, test the risky flows, and decide when you need a professional audit.
Need a second pair of eyes? Explore our code audit services, scope and pricing, and client case studies.