A common footgun with Express: the popular cors npm package, when configured with no origin option or with origin: true, reflects back whatever Origin header the request sent as Access-Control-Allow-Origin. That effectively allows every origin while looking like a locked-down config — it works fine until someone adds credentials: true and realizes any site can now make authenticated requests on a logged-in user's behalf.
The Same-Origin Policy
By default, browsers enforce the Same-Origin Policy: JavaScript running on a page from one origin (domain + scheme + port) can't read responses from requests made to a different origin. This is a fundamental security mechanism that stops a malicious script on one site from stealing data from another site where the user happens to be logged in.
How CORS relaxes that policy
CORS (Cross-Origin Resource Sharing) is a set of HTTP headers a server uses to explicitly allow certain (or all) outside origins to read its responses. The key header is Access-Control-Allow-Origin, which specifies which domains are permitted.
The wildcard-plus-credentials trap
When a request is sent with credentials: 'include' — needed to send a session cookie to an API on a different subdomain — browsers flatly refuse to accept Access-Control-Allow-Origin: * in the response. The spec explicitly forbids combining a wildcard origin with credentials; the server must echo back the exact requesting origin instead.
Why you'd need this
- Diagnosing a CORS error and figuring out exactly which headers the server is missing.
- Catching an overly permissive
corsmiddleware config before it ships to production. - Understanding the difference between "simple" requests and preflight (OPTIONS) requests.
CORS doesn't protect the server from attacks
CORS is a mechanism that only restricts browsers and only JavaScript code running on a web page; it does absolutely nothing to stop an attacker from sending the same request directly via curl, Postman, or a backend script, bypassing the browser entirely. That's why CORS should never be treated as a substitute for real server-side authorization — it's a tool for controlling which sites can use an API from a user's browser, not a barrier against attacks in general.