You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I ran into a subtle issue with the default allowedHeaders: true and exposeHeaders: true behavior on non-preflight requests, and wanted to share a concrete real-world example where it causes problems.
What happens
When either option is set to true, the plugin calls processHeaders(request.headers) on every non-preflight response. This extracts all incoming request header keys and echoes them back as the value of the corresponding CORS response header.
Real-world impact
Our API sits behind Cloudflare, so every request arrives with a long tail of proxy headers: cf-connecting-ip, cf-ipcity, cf-ipcontinent, cf-ray, cdn-loop, x-forwarded-for, x-forwarded-proto, all the sec-fetch-* and sec-ch-ua-* headers, and more. With the current defaults, our responses ended up looking like this:
The exposeHeaders list is particularly problematic: Access-Control-Expose-Headers is meant to declare which response headers the browser may expose to JavaScript, but here it's being populated with request header names — headers the server never sends back as response headers.
Workaround
We worked around it by explicitly setting both options:
This works, but the default still feels unexpected — especially for exposeHeaders, where echoing request headers is semantically an odd default.
Existing PR
I noticed there's already a PR open that addresses part of this: #66 (Allow allowedHeaders and exposeHeaders to receive false).
It's been open for about a year without activity. Adding false as an accepted value would be a clean way to opt out entirely without needing to pass an empty array as a workaround.
Summary
I ran into a subtle issue with the default
allowedHeaders: trueandexposeHeaders: truebehavior on non-preflight requests, and wanted to share a concrete real-world example where it causes problems.What happens
When either option is set to
true, the plugin callsprocessHeaders(request.headers)on every non-preflight response. This extracts all incoming request header keys and echoes them back as the value of the corresponding CORS response header.Real-world impact
Our API sits behind Cloudflare, so every request arrives with a long tail of proxy headers:
cf-connecting-ip,cf-ipcity,cf-ipcontinent,cf-ray,cdn-loop,x-forwarded-for,x-forwarded-proto, all thesec-fetch-*andsec-ch-ua-*headers, and more. With the current defaults, our responses ended up looking like this:The
exposeHeaderslist is particularly problematic:Access-Control-Expose-Headersis meant to declare which response headers the browser may expose to JavaScript, but here it's being populated with request header names — headers the server never sends back as response headers.Workaround
We worked around it by explicitly setting both options:
This works, but the default still feels unexpected — especially for
exposeHeaders, where echoing request headers is semantically an odd default.Existing PR
I noticed there's already a PR open that addresses part of this: #66 (
Allow allowedHeaders and exposeHeaders to receive false).It's been open for about a year without activity. Adding
falseas an accepted value would be a clean way to opt out entirely without needing to pass an empty array as a workaround.Suggestion
Would the team be open to one of these?
exposeHeaderson non-preflight requests — echoing all request headers doesn't quite match the purpose of the headerThanks for taking a look, and happy to help with a PR if there's a preferred direction!