TL;DR: A CORS error is not a bug to silence with a wildcard. If your endpoint sits behind a login, Access-Control-Allow-Origin: * with credentials lets any site read your users' data. The fix is a short allow-list, not a wildcard.
Here is how it starts. You ship an app built with an AI tool. A call to your own API fails in the browser. The console shows a CORS error. You paste it into the chat. The AI tells you to add one header: Access-Control-Allow-Origin: *. The error goes away. You move on.
That header is the problem. It did not fix a bug. It opened a door.
This is common in AI-built code. A Carnegie Mellon test found that only about 10.5% of AI-generated code passed a security review. The code runs. It just does not hold up. CORS is one of the spots where it fails most.
Check your own app first with the free scan. No code access. No install. About 60 seconds. Then read on to see what the wildcard really does.
*.What CORS Actually Does
Your browser follows one core rule. Code on one site cannot read a response from another site. This rule is called the same-origin policy. It is what stops a random web page from reading your bank account in another tab.
But real apps do need to talk across sites. Your front end may live on one domain. Your API may live on another. So the browser needs a way to allow that on purpose. CORS is that way.
CORS is a set of response headers. The server uses them to say who is allowed to read its data. The main one is Access-Control-Allow-Origin. It names the site that may read the response. A value of * means "any site at all."
One more header matters here: Access-Control-Allow-Credentials. When it is set to true, the browser sends cookies and logged-in session data with the request. And it lets the calling site read the reply.
Put those two together and you have the hole.
The Wildcard That Becomes a Hole
Say your API returns private data. A user profile. An order list. A list of your customers. It checks a login cookie before it answers. That is normal and good.
Now you add Access-Control-Allow-Origin: * to stop the CORS error. You also set Access-Control-Allow-Credentials: true so the login still works. It feels like both boxes are ticked.
Here is what you just allowed. A user visits a bad site while logged in to yours. That site runs a small script. The script calls your API. The browser sends your user's cookie. Your server checks the cookie, sees a valid login, and returns the private data. Your CORS headers then let the bad site read it.
Access-Control-Allow-Origin: * combined with Access-Control-Allow-Credentials: true is a critical CORS misconfiguration. Any website can make credentialed cross-origin requests, stealing session data. This is the exact text our Security scanner returns when it finds this pairing, at 0.99 confidence.
There is a catch that makes this worse. The browser will not allow a literal * together with credentials. So the "fix" that gets copied around does something sneakier. It reads the origin from the request and sends that same value back. This is called origin reflection. It looks safe. It is not. It means the server trusts every origin that asks. That is the same as a wildcard, just hidden.
The server reflected back an untrusted origin in Access-Control-Allow-Origin. This allows any website to make cross-origin requests as if from your own domain. Our scanner flags reflected origins at 0.98 confidence, right next to the wildcard check.
Why Vibe-Coded Apps Hit This So Often
AI tools learn from public code. A lot of that public code is sample code. Sample code turns CORS off with a wildcard so the demo just runs. The model saw that pattern a million times. So it hands you the same line.
The tool is not trying to hurt you. It is trying to make the error go away. A wildcard makes every CORS error go away. That is why it shows up first.
Supabase is a good example. Supabase sets CORS on its own hosted API for you. But Edge Functions are code you write. Each one sets its own headers. Almost every Edge Function tutorial starts with a wildcard block, because it keeps the demo short. That block then gets pasted into real apps that hold real user data.
This is the same pattern behind CVE-2025-48757, the Supabase exposure that hit 170+ vibe-coded apps. The platform was fine. The config left to the builder was not. CORS is the same story. The tool ships. The safe setup is on you.
The rule of thumb: if a page needs a login to see the data, it must never answer a site you did not put on your list.
How to Fix CORS the Right Way
The safe pattern is short. Keep a list of the origins you trust. Check each request against that list. If the origin is on the list, send it back. If not, send nothing. Never send * on a page behind a login.
Step 1: List the origins you trust
Write down the exact sites that should call your API. Your live front end. Your staging site. Your local dev URL. That is usually the whole list. Keep it small.
const ALLOWED = [ "https://app.yoursite.com", "https://yoursite.com", "http://localhost:3000" ];
Step 2: Match the request, then echo one origin
Read the origin from the request. Check it against the list. Send it back only if it matches. This is the core fix in a Supabase Edge Function:
const origin = req.headers.get("Origin") || "";
const allow = ALLOWED.includes(origin) ? origin : "";
const headers = {
"Access-Control-Allow-Origin": allow,
"Access-Control-Allow-Credentials": "true",
"Vary": "Origin"
};
Note the Vary: Origin line. It tells caches to store one copy per origin. Without it, a cache can hand the wrong origin to the wrong user. Small line, real bug if you skip it.
Step 3: Handle the preflight
For many calls, the browser sends a test request first. It uses the OPTIONS method. This is the preflight. Answer it with your allowed methods and headers, and stop there:
if (req.method === "OPTIONS") {
return new Response("ok", {
headers: {
...headers,
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Headers": "authorization, content-type"
}
});
}
Step 4: Only send credentials when you need them
Does the endpoint use a login cookie? Then keep Allow-Credentials: true, and keep the strict list above. Does it serve fully public data with no login? Then you can use * and drop credentials. Pick one. Never mix a wildcard with credentials.
Check your app for a CORS hole now
Free scan. Live URL. No code access. Results in about 60 seconds.
Run the free scanA 4-Point CORS Check Before You Launch
- No wildcard on private pages. Search your code for
Allow-Origin: *. Remove it from any route behind a login. - No blind reflection. Make sure you never send back an origin without checking it against a list first.
- Credentials are scoped. If
Allow-Credentialsistrue, the origin must come from your trusted list, never from*. - Vary on Origin. Add the
Vary: Originheader so caches do not leak the wrong origin.
Run these four checks on every API route and every Edge Function. Most vibe-coded apps pass three and miss one. The one they miss is usually the wildcard on a logged-in route.
What Comes After the Free Scan
The free scan gives you a Launch Readiness Score out of 100. It checks your live app for the wildcard pairing, for reflected origins, and for the other top security gaps. CORS issues show up under Security. They are rated P0 or P1 based on what data is at risk.
Want the full list with a fix and a time estimate for each issue? The Launch Readiness Audit ($499) covers every gap across all four areas. Want the fixes done for you as pull requests you approve? The DFY Technical Setup handles that, and CORS hardening is part of the API security work.
For the related setup that most often ships broken next to CORS, read our guide on Supabase row level security for vibe-coded apps, or run a full Supabase security audit.
Frequently Asked Questions
What is a CORS misconfiguration in plain terms?
It is a server rule that lets the wrong websites read your data. The worst kind pairs a wildcard or reflected origin with Access-Control-Allow-Credentials: true. That lets any site read the data of your logged-in users.
Is Access-Control-Allow-Origin: * safe?
It is safe only on public endpoints with no login and no private data. Behind a login it is a risk. Send back one specific trusted origin instead of *.
How do I fix a CORS error without a wildcard?
Keep a short list of origins you trust. Check the request origin against that list. If it matches, echo that one origin back. If it does not, send nothing. Never reflect an origin you did not check.
Does Supabase set up CORS for me?
Supabase handles CORS on its own hosted API. But Edge Functions you write set their own headers. That is where most wildcard mistakes happen in vibe-coded apps.
How do I check my app for a CORS problem?
Run a free scan at launchreadycode.com. It checks your live app for a wildcard origin with credentials and for reflected origins. No code access. Results in about 60 seconds.