VibeSecurity

Security check

CORS misconfiguration: the settings that expose your API

CORS controls which websites' scripts may read responses from your API in a browser. It is not authentication, and a wrong setting can let another site read a logged-in user's data.

By the VibeSecurity team1 min read

Patterns to remove

  • Access-Control-Allow-Origin set from the incoming Origin header without checking it against a list.
  • Access-Control-Allow-Origin: * on an endpoint that returns private data.
  • Allowing the null origin.
  • Trusting any subdomain by pattern match, such as an endsWith check that also matches an attacker's look-alike domain.

An allow-list that works

Express middleware
const allowed = new Set(['https://app.example.com', 'https://www.example.com']);

app.use((req, res, next) => {
  const origin = req.headers.origin;
  if (origin && allowed.has(origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
    res.setHeader('Vary', 'Origin');
    res.setHeader('Access-Control-Allow-Credentials', 'true');
  }
  next();
});

What CORS will not do

CORS is enforced by browsers. A script, curl or another server can call your API directly, so the API must still check who is asking on every request.

Test it on your own API

Terminal
curl -sI https://your-api.example/endpoint \
  -H 'Origin: https://not-allowed.example' | grep -i access-control

Frequently asked questions

Is Access-Control-Allow-Origin: * always wrong?

No. It is fine for public data such as a public asset or open API. It is wrong for responses that depend on the user.

Why does my browser block the request but curl works?

CORS is a browser rule. It restricts what page scripts may read, not what the server accepts.

Sources

  1. 1.MDN: Cross-Origin Resource Sharing