webzod
account

Replace CORS origin reflection with an allow-list on nginx

headers.cors.reflected_credentials · effort: about an hour

Why it matters

The server copies any Origin into Access-Control-Allow-Origin and allows credentials, so any website a logged-in visitor opens can read your responses with their cookies. Only origins on a fixed list should ever get that permission.

Staged change. Do this in stages and check each one before the next, so a mistake does not break your site or your mail.

The fix

  1. Stage 1: replace any add_header Access-Control-Allow-Origin $http_origin with the allow-list below. Put the map blocks in the http context, list your real origins, and if the application sets CORS headers itself, hide them with proxy_hide_header (or fastcgi_hide_header for PHP-FPM) so only nginx's copy is sent.
  2. Put these lines in the server block, or in a location that already includes your shared security-headers snippet. add_header and proxy_hide_header lines in a location replace the server-level ones (nginx 1.29.3 and later can use add_header_inherit merge; for add_header).
  3. Stage 2: run sudo nginx -t, reload, and test your front ends. An empty value means nginx does not send the header, so other origins get no CORS headers.
nginx
# http {} context: exact origins only
map $http_origin $cors_allow_origin {
    default "";
    "https://app.example.com" $http_origin;
}
map $cors_allow_origin $cors_allow_credentials {
    ""      "";
    default "true";
}

# server {} block (or a location that already includes your security headers)
proxy_hide_header Access-Control-Allow-Origin;
proxy_hide_header Access-Control-Allow-Credentials;
add_header Access-Control-Allow-Origin $cors_allow_origin always;
add_header Access-Control-Allow-Credentials $cors_allow_credentials always;
add_header Vary Origin always;

The examples use example.com. Replace it with your own domain.

Read the documentation (opens in a new tab)

Scan your domain to see whether this applies to you.