VULNEXUSAI · BLOG
CORS explained: what it is and how to configure it safely
CORS decides whether a website can access resources from another origin. Understand how it works, which configurations are dangerous (origin reflection, wildcard with credentials) and how to configure it.
CORS (Cross-Origin Resource Sharing) is a browser mechanism that decides whether a website can access resources from another origin — an API, an image or a script on a different domain. Misconfigured, it opens the site to abuse; configured well, it stays invisible. It is also one of the areas where the most common mistakes are the most dangerous.
What CORS is
When JavaScript from site-a.com tries to fetch a resource from api-b.com, the browser applies the same-origin policy: by default, the request is blocked. CORS is the exception declared by the server itself: api-b.com responds with headers authorizing site-a.com to read the response.
The main headers are:
Access-Control-Allow-Origin— which origins may access the resource (https://site-a.comor*).Access-Control-Allow-Credentials— whether cookies and credentials can be sent.Access-Control-Allow-Methods— allowed methods (GET,POST, etc.).Access-Control-Allow-Headers— allowed request headers.Access-Control-Max-Age— how long the browser may reuse the preflight result.
How it works in practice
For requests that can cause side effects (methods other than simple GET/POST, or custom headers), the browser first sends a preparation request called preflight, with the OPTIONS method. The server answers which origins, methods and headers it accepts, and only then the browser sends the real request.
For simple requests there is no preflight: the browser just checks the Access-Control-Allow-Origin header on the actual response.
The key point: the blocking happens in the browser, not on the server. The server sends the resources normally; the browser is the one that prevents JavaScript from another origin from reading the response. This protects the user, not the server.
Dangerous configurations
Two configurations lead the list of failures in security audits:
Wildcard with credentials — combining Access-Control-Allow-Origin: * with Access-Control-Allow-Credentials: true. Browsers reject the combination, but many servers emit it anyway, breaking both security and functionality at the same time. With credentials, the origin must be explicit, never *.
Origin reflection — the server echoes back any Origin header value it receives:
res.setHeader("Access-Control-Allow-Origin", request.headers.origin);
This way, any malicious site can send Origin: https://evil-site.com and receive authorization to read the response — including with credentials when combined with Allow-Credentials. This is the pattern exploited in CORS abuse attacks.
How to configure it
Express (Node.js):
const allowedOrigins = ["https://site-a.com", "https://app.site-a.com"];
app.use((req, res, next) => {
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader("Access-Control-Allow-Origin", origin);
}
res.setHeader("Access-Control-Allow-Credentials", "true");
next();
});
nginx:
location /api {
if ($http_origin = "https://site-a.com") {
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Credentials true;
}
}
General rule: keep a fixed allowlist of known origins. If the resource is public and uses no credentials, Access-Control-Allow-Origin: * is acceptable — but never with Allow-Credentials.
Already understand the mechanism but stuck on a CORS error in production right now? See the practical guide to fixing CORS errors in Node.js and Nginx, with ready-to-use allowlist and Vary: Origin examples.
Common mistakes
- Reflecting the received
Origin: any site gets access. Use an allowlist. *withAllow-Credentials: true: invalid and dangerous; browsers reject it.- Wildcard on authenticated APIs: resources that use session cookies need explicit origins.
- Opening CORS to everything "to keep it simple": you lose the browser's origin boundary.
- Testing only with curl: curl does not apply origin policy; what matters is browser behavior.
- Leaking internal origins: admin, staging or intranet origins should never appear in the allowlist.
How to check it
The VulnexusAI scanner tests the site with a sample Origin and checks three things: the wildcard-with-credentials combination, whether the sent origin is reflected back, and the behavior for public resources. Every failure comes with the suggested fix in the report.
Read in PortugueseRead in Spanish
Frequently asked questions
Is CORS a security feature that protects my server?
Not exactly. CORS is enforced by the browser to protect the user, not the server — it restricts what a web page running in the browser can read from a cross-origin response. A server without CORS restrictions is still directly reachable by tools like curl or another server; CORS doesn't block that.
Can I just set Access-Control-Allow-Origin to the request's Origin for every domain?
Only if you also don't need Access-Control-Allow-Credentials: true. Reflecting any origin without an allowlist defeats the purpose of CORS for authenticated requests, since it effectively behaves like a wildcard for every caller.
Why does my request work in Postman but fail in the browser with a CORS error?
Tools like Postman aren't subject to the browser's same-origin policy, so they never trigger CORS checks. CORS errors are enforced client-side by browsers only — the request itself often reaches the server fine either way, which is why server logs may show a successful response even though the browser blocked it.
Test any public URL with the free VulnexusAI scanner and get a score from 0 to 100, with a grade from A to F and fix tips.
Check my website