Severity: low — but real. Caching layers may serve a response with the wrong Access-Control-Allow-Origin to a different origin.
Surfaced by: titan Phase 2.6 (Wheels 4.0 upgrade), 2026-05-15.
Description
When wheels.middleware.Cors reflects an allowed origin back via Access-Control-Allow-Origin: <origin>, it does not also emit Vary: Origin. CDN, reverse-proxy, and browser disk caches may then serve a cached response with the wrong ACAO to a subsequent request from a different origin, breaking CORS for that request or (worse) leaking a cached response to a different cross-origin caller.
The legacy Global.cfc:$setCORSHeaders (3.x global-setting path) at line 3564 DOES emit Vary: Origin. The new middleware should at least match.
Suggested fix
One-line addition in vendor/wheels/middleware/Cors.cfc alongside the existing cfheader(name=\"Access-Control-Allow-Origin\", ...) block:
cfheader(name=\"Vary\", value=\"Origin\");
Optionally append to an existing Vary header rather than replacing it, if other middleware emits Vary first.
cc @bpamiri
Severity: low — but real. Caching layers may serve a response with the wrong
Access-Control-Allow-Originto a different origin.Surfaced by: titan Phase 2.6 (Wheels 4.0 upgrade), 2026-05-15.
Description
When
wheels.middleware.Corsreflects an allowed origin back viaAccess-Control-Allow-Origin: <origin>, it does not also emitVary: Origin. CDN, reverse-proxy, and browser disk caches may then serve a cached response with the wrong ACAO to a subsequent request from a different origin, breaking CORS for that request or (worse) leaking a cached response to a different cross-origin caller.The legacy
Global.cfc:$setCORSHeaders(3.x global-setting path) at line 3564 DOES emitVary: Origin. The new middleware should at least match.Suggested fix
One-line addition in
vendor/wheels/middleware/Cors.cfcalongside the existingcfheader(name=\"Access-Control-Allow-Origin\", ...)block:Optionally append to an existing
Varyheader rather than replacing it, if other middleware emits Vary first.cc @bpamiri