[{"data":1,"prerenderedAt":380},["ShallowReactive",2],{"blog-en-cors-wildcard-security-risk":3},{"id":4,"title":5,"body":6,"category":339,"cover":340,"coverAlt":341,"description":342,"draft":343,"extension":344,"faq":345,"image":361,"keywords":362,"meta":369,"navigation":370,"ogTitle":30,"path":371,"published":372,"seo":373,"stem":374,"tldr":375,"updated":372,"__hash__":379},"blog_en\u002Fblog\u002Fcors-wildcard-security-risk.md","Is a CORS wildcard a security risk? Usually not.",{"type":7,"value":8,"toc":327},"minimark",[9,18,26,31,34,44,47,50,54,57,63,66,72,75,79,82,85,168,175,178,182,193,196,202,207,210,214,217,220,229,232,236,239,257,263,271,278,282,307,314],[10,11,12,13,17],"p",{},"Your scan came back with a line that reads like an alarm: your API is open to\nany website. Or somebody technical looked at what your server sends back and\ntold you your app has a CORS wildcard, which is the character ",[14,15,16],"code",{},"*",", which\napparently means everybody.",[10,19,20,21,25],{},"Here is the part that guide after guide gets wrong: ",[22,23,24],"strong",{},"the wildcard is almost\nnever what opened your API."," It is an instruction your server attaches to its\nanswers, addressed to the browsers of people sitting on other websites, and it\narrives after the answer has already gone out. Restricting it stops another\nwebsite's page from reading your data. It does nothing about anyone reading it\nwithout a browser at all.",[27,28,30],"h2",{"id":29},"is-a-cors-wildcard-a-security-risk","Is a CORS wildcard a security risk?",[10,32,33],{},"On its own, hardly ever. It turns into one the moment something private is\nanswering behind it.",[10,35,36,37,39,40,43],{},"The wildcard is the value ",[14,38,16],{}," in a response header called\n",[14,41,42],{},"Access-Control-Allow-Origin",", and it means that any website's code may read\nthis particular answer. That sounds like a statement about who can reach your\ndata. It is a statement about who may read what your server has already sent.",[10,45,46],{},"The address a scan checks is the one your app is served from. On most builders\nthat address hands out your pages, your images and your compiled code, all of\nwhich go to every visitor by design. A wildcard on those grants permission to\nread files anybody could already download by opening your site.",[10,48,49],{},"So the finding is a question rather than a verdict, and the question is what\nsits behind the header. If the answer is your homepage, nothing happened. If\nthe answer is a list of your customers, that list was already reachable by\nanyone holding the address.",[27,51,53],{"id":52},"what-access-control-allow-origin-actually-does","What Access-Control-Allow-Origin actually does",[10,55,56],{},"It tells your visitor's browser whether the page on screen is allowed to look\nat an answer your server has already sent.",[10,58,59,60,62],{},"The order is the whole thing, and it runs backwards from how nearly everyone\npictures it. A page on some other website runs a piece of code that asks your\napp for data. The request goes out. Your server receives it, runs whatever it\nruns, and sends the response back in full. Only then does the browser read the\nheader on that response and decide whether to hand the contents to the page\nthat asked for them. MDN's own CORS guide puts it in one line: the server has\nto opt in with ",[14,61,42],{}," to share the response with the\nscript.",[10,64,65],{},"Your data left the building either way. What the header decides is whether one\nparticular piece of code, running inside one person's browser, gets to see it.",[67,68],"diagram",{"alt":69,"caption":70,"src":71},"One server answering two callers with an identical response. In the top lane the response reaches a browser, which holds it at a barrier so the page behind it receives nothing. In the bottom lane there is no barrier at all and the same response arrives intact at a terminal window.","Both callers get an answer, because the server sends one before anything is checked. The barrier in the top lane is the browser, and the bottom lane has no browser in it.","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fwho-reads-the-header-1600x650.png",[10,73,74],{},"The browser is the only thing in that story that reads the header. A script on\na server, a command line tool, a scraper, a mobile app: none of them consult\nit, because it was written for a browser and no browser is involved. They send\nthe same request, get the same response, and read every byte of it.",[27,76,78],{"id":77},"restricting-cors-does-not-make-an-open-endpoint-private","Restricting CORS does not make an open endpoint private",[10,80,81],{},"Because CORS lives inside browsers, and somebody helping themselves to your\ndata has no reason to use one.",[10,83,84],{},"This is the part that costs people an afternoon. They see the wildcard finding,\nnarrow the header to their own domain, redeploy, re-scan, and the address that\nwas handing out customer rows is still handing out customer rows. It always\nwas. The only caller who ever stopped was somebody else's web page.",[86,87,88,109],"table",{},[89,90,91],"thead",{},[92,93,94,98,103,106],"tr",{},[95,96,97],"th",{},"What someone tries",[95,99,100,101],{},"Wildcard ",[14,102,16],{},[95,104,105],{},"Your domain only",[95,107,108],{},"Any origin echoed back, credentials allowed",[110,111,112,125,136,148],"tbody",{},[92,113,114,118,121,123],{},[115,116,117],"td",{},"Opening the address in a browser tab",[115,119,120],{},"Works",[115,122,120],{},[115,124,120],{},[92,126,127,130,132,134],{},[115,128,129],{},"Reading it from a script or a terminal",[115,131,120],{},[115,133,120],{},[115,135,120],{},[92,137,138,141,143,146],{},[115,139,140],{},"Another website's page reading it",[115,142,120],{},[115,144,145],{},"Blocked",[115,147,120],{},[92,149,150,153,159,163],{},[115,151,152],{},"Another website reading it as your signed-in user",[115,154,155],{},[156,157,145],"key-verdict",{"type":158},"safe",[115,160,161],{},[156,162,145],{"type":158},[115,164,165],{},[156,166,120],{"type":167},"danger",[10,169,170,171,174],{},"Read the bottom row twice, because it is where the generic advice falls over. A\nplain wildcard cannot be used to read data belonging to your signed-in visitor.\nBrowsers refuse that combination outright, and MDN's CORS guide says so\ndirectly: if a request carries a cookie and the response comes back with\n",[14,172,173],{},"Access-Control-Allow-Origin: *",", the browser blocks access to the response and\nreports a CORS error in the console. So the wildcard, of all things, is what\nmakes that particular attack impossible.",[10,176,177],{},"The column that does hand over a signed-in user's data is the third one, and it\nneeds the server to write the caller's own address into its answer.",[27,179,181],{"id":180},"the-cors-setting-that-is-genuinely-dangerous","The CORS setting that is genuinely dangerous",[10,183,184,185,188,189,192],{},"A server that reads the ",[14,186,187],{},"Origin"," header off the request, writes that same value\ninto its own answer, and sends ",[14,190,191],{},"Access-Control-Allow-Credentials: true","\nalongside it.",[10,194,195],{},"Nobody sets out to do this. It arrives at the end of an afternoon spent trying\nto make a wildcard work with logged-in requests and discovering that it never\nwill. Echoing back whichever origin asked looks like the way through: every\nsite that should be allowed is allowed, the console errors stop, the feature\nships. What the server is actually saying is that the caller decides, and that\nincludes a page nobody has written yet.",[10,197,198,199,201],{},"Here is what it permits. Your customer is signed into your app, with a session\ncookie sitting in their browser. In another tab they open a site with nothing\nto do with you. That site's code asks your API for their account. Their browser\nattaches the cookie, because attaching cookies is what browsers do. Your server\nreads an ",[14,200,187],{}," it has never heard of, stamps it into the response as\npermission, and adds that credentials are fine. The browser checks, finds a\nmatch, and hands your customer's data to a page your customer never knew was\nreading it.",[67,203],{"alt":204,"caption":205,"src":206},"A request leaving an unknown website carrying a red name tag and a cookie. The server copies the identical red tag into the permission field of its response. The browser compares the two tags, finds them the same, and passes the data through to the page.","The caller supplies the name, and the server writes that name onto the pass. Whoever asks is on the list, which is what makes this shape different from a wildcard.","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fthe-echoed-origin-1600x680.png",[10,208,209],{},"In our August 2026 sweep this turned up on 61 of the 30,926 apps where the\ncheck could get an answer. Of the three CORS findings, it is the only one that\nreaches data sitting behind a login.",[27,211,213],{"id":212},"how-often-a-wildcard-turns-up-and-who-decides-it","How often a wildcard turns up, and who decides it",[10,215,216],{},"Mostly your builder decides. In that same sweep, 5,727 of those 30,926 apps\nsent a wildcard, and the best single predictor of whether yours does is which\nplatform published it.",[10,218,219],{},"The CORS check reported at least one finding on 5,418 of the 5,419 Base44 apps\nwhere it got an answer, and on 8 of the 18,518 Lovable ones. Replit sat between\nthem at 1,129 of 3,037. A spread that wide is what a hosting default looks like\nfrom outside: near-total on one platform, close to absent on another, across\nthousands of apps whose owners never coordinated anything.",[10,221,222,223,228],{},"Three separate findings make up the CORS check across all 30,926 apps: a\nwildcard on 5,727 of them, an address answering with data and no login on\n3,852, and the echoed-origin shape on 61. Those add up to more than the check\ndoes, because plenty of apps have two of the three. Every figure here comes\nfrom\n",[224,225,227],"a",{"href":226},"\u002Fresearch\u002Fvibe-coded-app-security-2026","our scan of 30,998 live vibe-coded apps",",\nwhich publishes each one with the base it was measured over.",[10,230,231],{},"Which of those you can do anything about splits the same way. The wildcard is\nsent by whoever serves your app, and for a vibe-coded app that is usually the\nbuilder. What comes back when a stranger asks one of your addresses for data\nwas decided inside your app, by you or by the builder writing code on your\nbehalf.",[27,233,235],{"id":234},"how-to-check-your-own-app","How to check your own app",[10,237,238],{},"Two things to look at, and the second is the one that decides whether any of\nthis matters.",[10,240,241,244,245,248,249,252,253,256],{},[22,242,243],{},"Does your app send a wildcard?"," Open your live app, press F12 to bring up\nthe browser's developer tools, click ",[22,246,247],{},"Network",", and reload the page. Click\nthe first request in the list and read the ",[22,250,251],{},"Response Headers"," panel. A line\nreading ",[14,254,255],{},"access-control-allow-origin: *"," is the finding. No such line at all\nmeans your server shares nothing across origins with anybody.",[10,258,259,262],{},[22,260,261],{},"What answers behind it?"," Stay in the Network tab and reload your app while\nsigned in, watching for requests that come back as JSON. Those are the\naddresses your app fetches data from. Copy each URL, open a private browsing\nwindow so that you are signed out, and paste them in one at a time. Anything\nthat comes back carrying real rows, instead of an error or an empty list, is\nreadable by anyone on the internet who has that URL. That is true today,\nwhatever your CORS header says, and it stays true after you narrow it.",[10,264,265,266,270],{},"Our free scan runs the second check for you: it reads your app's code for the\naddresses it calls, requests each one with no login, and reports the ones that\nanswered with data. It takes about 20 seconds and needs no account:\n",[224,267,269],{"href":268},"\u002F#scan","scan your app",".",[10,272,273,274,270],{},"If your app talks to Supabase straight from the browser, there is a third place\nto look, because the rules on each table decide who may read which rows and\n",[224,275,277],{"href":276},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","switching them on is not the same as being protected",[27,279,281],{"id":280},"what-to-do-right-now","What to do right now",[283,284,285],"key-takeaways",{},[286,287,288,292,295,298,304],"ul",{},[289,290,291],"li",{},"Treat a wildcard finding as a question about what is behind the header. On the address your app is served from, it usually permits reading files every visitor downloads anyway.",[289,293,294],{},"Sign out and open every data address your app calls. Anything that returns real rows to a signed-out browser is public to everybody, whatever the header says.",[289,296,297],{},"Fix an open address at the address: require a login and answer a stranger with a 401. Narrowing the CORS header leaves it reachable by everything except other people's web pages.",[289,299,300,301,303],{},"If your server echoes back whichever origin asked and sends ",[14,302,191],{},", replace that with a list of your own domains today. It is the one shape here that lets another site read data as your signed-in user.",[289,305,306],{},"If the header comes from your builder's hosting and you cannot change it, spend the time on the endpoints instead. That is where your data is.",[10,308,309,310,270],{},"The habit worth keeping is the signed-out pass over your own data addresses,\nbecause a new feature adds a new one every time and nothing on screen looks\ndifferent when one of them starts answering. Reeve Care re-runs this scan\nagainst your live app on a schedule and emails you when a result gets worse:\n",[224,311,313],{"href":312},"\u002F#pricing","what it watches and what it costs",[10,315,316,317,321,322,326],{},"If you would rather work through everything in one sitting, the\n",[224,318,320],{"href":319},"\u002Fchecklist","10-minute security checklist"," covers this next to the rest of what\na newly launched app tends to leave open, and\n",[224,323,325],{"href":324},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","which keys are safe in your frontend","\nis the other half of the question people usually arrive with.",{"title":328,"searchDepth":329,"depth":329,"links":330},"",3,[331,333,334,335,336,337,338],{"id":29,"depth":332,"text":30},2,{"id":52,"depth":332,"text":53},{"id":77,"depth":332,"text":78},{"id":180,"depth":332,"text":181},{"id":212,"depth":332,"text":213},{"id":234,"depth":332,"text":235},{"id":280,"depth":332,"text":281},"Security basics","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcover-1200x630.png","Six different callers reaching one server, with the same answer travelling back out to every one of them.","Is a CORS wildcard a security risk? Usually it is your builder default, and it gives away nothing your server was not already handing to anyone who asked.",false,"md",[346,349,352,355,358],{"q":347,"a":348},"My scan says my API is open to any website. Do I have to fix it?","Look at what answers behind it first. A wildcard on the address your app is served from usually permits reading your pages, images and compiled code, all of which every visitor downloads anyway. Fix it when an address behind that header returns real data to somebody who is not signed in, and fix it at that address by requiring a login.",{"q":350,"a":351},"Does restricting CORS to my own domain make my API private?","No. CORS is a rule browsers apply to themselves, so it only ever governs code running on somebody else's web page. A script, a terminal command or a scraper sends the same request and reads the same answer, because none of them consult the header. If an address returns your data without a login, it does that for everyone, whatever the header says.",{"q":353,"a":354},"Can another website read my logged-in users data because of a wildcard?","Not with a plain wildcard. Browsers refuse that combination: MDN's CORS guide states that when a request carries a cookie and the response comes back with Access-Control-Allow-Origin set to the wildcard, the browser blocks access to the response and logs a CORS error. The version that does work is a server echoing back whichever origin asked, together with Access-Control-Allow-Credentials set to true.",{"q":356,"a":357},"How do I change the CORS header on a Lovable or Base44 app?","Often you cannot, because the header is sent by the hosting the builder publishes to and it applies to every app on that platform. That is worth knowing before you spend a week on it. What you can always change is what your own endpoints hand back to a request with no login, and that is where the fix belongs anyway.",{"q":359,"a":360},"My scan flagged open API endpoints as well. Is that the same finding?","It is a different one, and the more serious of the two. A wildcard describes who may read an answer. An open endpoint means the answer contained your data and arrived without anybody signing in. The second is true for a browser, a script and a stranger with the URL alike, and narrowing your CORS header changes none of it.","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",[363,364,365,366,367,368],"cors wildcard security risk","access-control-allow-origin wildcard","is a cors wildcard dangerous","cors misconfiguration","api open to any website","access-control-allow-credentials true",{},true,"\u002Fblog\u002Fcors-wildcard-security-risk","2026-08-26",{"title":5,"description":342},"blog\u002Fcors-wildcard-security-risk",[376,377,378],"A CORS wildcard is a security risk only when something private answers behind it. By itself it permits reading things anyone could already download.","The header is an instruction to your visitor's browser and it arrives after the answer has been sent. Nothing outside a browser reads it, so restricting it leaves an open endpoint exactly as open.","The shape worth an evening is a server that echoes back whichever website is asking and allows credentials. That one lets another site read data as your signed-in user.","aK3urhL4H4iGOS331ywzBfQT5hYgnDXhFHe1BoGHDf4",1787826048204]