The Misconfiguration Scanverra Flags Most
The single most dangerous CORS mistake is sending both of these headers on the same response:
1Access-Control-Allow-Origin: *
2Access-Control-Allow-Credentials: trueModern browsers are supposed to refuse to expose the response when both are present, but Scanverra flags it as a critical finding regardless - some HTTP client libraries and older browser versions don't enforce that refusal consistently, and a server sending this pairing at all indicates the CORS policy wasn't actually designed, just switched on to make an error go away.
One step down in severity: Access-Control-Allow-Origin: *on its own, without credentials. If the endpoint returns anything user-specific or sensitive - even without cookies, maybe via a query-string token - a wildcard still lets any site's script read it.
How This Usually Happens
- Copy-pasted from a Stack Overflow answer.
Access-Control-Allow-Origin: *is the fastest way to make a CORS error disappear during development, and it often just stays in production. - A framework default nobody revisited. Some API scaffolding tools enable permissive CORS out of the box for local development convenience.
- Reflecting the Origin header to "support everyone". Dynamically echoing back whatever
Originthe browser sent, instead of checking it against an allowlist, achieves the same exposure as a wildcard while looking more deliberate in the response.
How to Fix It
1. Maintain an explicit allowlist
Validate the incoming Origin against a known list, and only echo it back if it matches:
1const ALLOWED_ORIGINS = ["https://app.example.com", "https://staging.example.com"];
2
3app.use((req, res, next) => {
4 const origin = req.headers.origin;
5 if (origin && ALLOWED_ORIGINS.includes(origin)) {
6 res.setHeader("Access-Control-Allow-Origin", origin);
7 res.setHeader("Vary", "Origin");
8 }
9 next();
10});2. Only set Allow-Credentials when you mean it
If the endpoint doesn't need cookies or HTTP auth sent cross-origin, don't set Access-Control-Allow-Credentials at all. If it does, it must be paired with a specific origin from step 1 - never a wildcard.
3. Scope CORS per-route, not globally
A public, read-only endpoint and an authenticated account API rarely need the same policy. Most frameworks let you apply CORS middleware selectively rather than one blanket rule for the whole app.
4. Don't forget preflight (OPTIONS) requests
Non-simple requests (custom headers, methods other than GET/POST) trigger a preflight OPTIONS request first - make sure your allowlist logic runs there too, not just on the actual request.
How Scanverra Detects This
Scanverra's security scan inspects the actual Access-Control-Allow-Origin and Access-Control-Allow-Credentials response headers on your site and flags the wildcard-plus-credentials combination as critical, and a bare wildcard on a non-public endpoint as medium severity - the same class of check used across its full header analysis.