Skip to main content

Confirm

Are you sure?

Extras · Checked on every page

CORS configurationWhat it checks and how to fix it

What it checks

Requests the page with an Origin header from an unrelated site (https://example.com) and reads the Access-Control-* headers that come back. No CORS headers passes, as it should for an ordinary website. It fails when Access-Control-Allow-Origin is * together with Access-Control-Allow-Credentials: true, and warns when the server echoes back whatever origin it is sent.

Why it matters

CORS decides which other websites may read your responses from a visitor's browser. A server that reflects any Origin, especially with credentials allowed, lets a malicious page make requests as your logged-in users and read the answers: their personal data, API keys or CSRF tokens. The wildcard plus credentials combination is rejected by browsers anyway, which usually means the configuration was written by trial and error and deserves a second look.

How to fix it

Only send CORS headers on endpoints that really are called from another origin, and answer with an allowlist instead of echoing the request's Origin.

nginx

map $http_origin $cors_origin {
  default "";
  "https://app.example.com" $http_origin;
  "https://admin.example.com" $http_origin;
}

location /api/ {
  add_header Access-Control-Allow-Origin $cors_origin always;
  add_header Access-Control-Allow-Credentials true always;
  add_header Vary Origin always;
}

Rails with the rack-cors gem:

# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins "https://app.example.com", "https://admin.example.com"
    resource "/api/*", headers: :any, methods: [:get, :post, :patch, :delete], credentials: true
  end
end

Cloudflare: CORS headers come from your origin; if you add them with a Transform Rule, use a fixed origin value rather than copying the request header.

For a truly public, read-only API, Access-Control-Allow-Origin: * is fine as long as you never also send Access-Control-Allow-Credentials: true.

Monitor this automatically

Full Stack Audit runs this check and 126 others on your site on a schedule, and emails you when one that passed starts failing.

More Extras checks