CORS misconfiguration is one of those findings that shows up on a scan report and gets skipped past because it sounds abstract. I want to walk through what it actually lets happen, in plain terms, because the real version of this is a lot more concrete and a lot more concerning than the jargon makes it sound.
The rule CORS exists to enforce
By default, a browser stops a script running on one website from making a request to a completely different website on a visitor's behalf, especially if that request would carry along the visitor's logged-in session. That default exists specifically so that a malicious site can't quietly ride along on whatever accounts a visitor happens to be logged into elsewhere. Cross-Origin Resource Sharing, CORS, is the mechanism a site's own server uses to deliberately loosen that default: 'requests from this other specific site are allowed to reach me.'
Used correctly, that's a normal and necessary thing. Plenty of legitimate setups need one of your own domains to talk to another one of your own domains. The problem is what happens when that door gets left open wider than intended.
What a misconfigured policy actually looks like
The most common version of this mistake is a server that reflects back whatever origin sent the request and says yes to all of them, sometimes paired with also allowing credentials to be included. In plain terms: any website on the internet, run by anyone, can make a request to your app and have that request carry along a real visitor's logged-in session, as long as that visitor happens to have your app open, or has visited recently, in another tab.
Walking through what that enables
- Someone builds a page that looks completely unrelated to your app, maybe a quiz, a game, an article, anything a visitor might click into.
- That page runs a script that quietly calls your app's API in the background, the same API your real frontend calls.
- Because your CORS policy allows any origin and includes credentials, the visitor's browser attaches their real session to that request, exactly as if they'd made it from your own site.
- Your server, seeing a valid session, responds with real data or performs a real action, believing the request came from your legitimate frontend.
- The malicious page reads that response and now has whatever data the visitor's session had access to, all without the visitor clicking anything beyond the page they were already looking at.
No password was stolen. No malware was installed. The visitor did nothing wrong beyond having two tabs open, one of which happened to be malicious. Your app simply trusted a request it should have refused.
How to actually check your own app
Look at your server's response headers for an Access-Control-Allow-Origin value. If it's set to a literal asterisk, meaning any origin, and Access-Control-Allow-Credentials is also set to true on the same response, that combination is the misconfiguration in its clearest form, and most frameworks will even warn you if you try to set both at once. If your policy instead reflects back whatever Origin header the request sent, rather than checking it against an actual allow-list, that's functionally the same problem wearing a different disguise.
What a correct policy looks like instead
List the specific origins that are actually allowed to make credentialed requests to your API, by exact domain, and reject everything else. If you don't know why a specific origin needs access, it probably doesn't need it. This is one of the rare security settings where being restrictive by default costs you almost nothing and being permissive by default costs you everything the moment someone builds a page designed to take advantage of it.