Describe the bug
The gateway and runtime CORS config reflect the request Origin back for any
domain while Access-Control-Allow-Credentials: true is set. Reflecting an
arbitrary origin together with credentials defeats the protection the browser
enforces (it blocks Access-Control-Allow-Origin: * with credentials precisely
to prevent this). Both spots carry the existing
// TODO: Configure allowed origins from environment:
apps/mesh/src/api/app.ts (CORS middleware, ~L1089)
packages/runtime/src/index.ts (DEFAULT_CORS_OPTIONS, ~L268)
origin: (origin) => {
if (origin.includes("localhost") || origin.includes("127.0.0.1")) return origin;
// TODO: Configure allowed origins from environment
return origin; // reflects any origin
},
credentials: true,
If session auth is cookie-based, a site the victim visits can issue credentialed
cross-origin requests to the gateway and read the responses (connections, tokens,
org data). The origin.includes("localhost") check is also bypassable
(https://localhost.attacker.com matches).
To Reproduce
- Start the gateway (
bun run dev)
curl -i -H "Origin: https://evil.example" http://localhost:3000/<any-endpoint>
- Response echoes
Access-Control-Allow-Origin: https://evil.example together
with Access-Control-Allow-Credentials: true
Expected behavior
Only allowlisted origins (plus localhost in dev) should be reflected. Implement
the existing TODO: read an allowlist from env (e.g. ALLOWED_ORIGINS,
comma-separated, exact match), centralize the duplicated logic, and don't
reflect non-allowlisted origins while credentials are enabled.
Open questions before a PR:
- Default permissive (opt-in to strict) to avoid breaking existing deployments,
or default-strict with an opt-out?
- Should
credentials be disabled for non-allowlisted origins, or is the
gateway intended to be called credential-less from arbitrary origins?
Happy to open a PR once the default behavior is agreed.
Describe the bug
The gateway and runtime CORS config reflect the request
Originback for anydomain while
Access-Control-Allow-Credentials: trueis set. Reflecting anarbitrary origin together with credentials defeats the protection the browser
enforces (it blocks
Access-Control-Allow-Origin: *with credentials preciselyto prevent this). Both spots carry the existing
// TODO: Configure allowed origins from environment:apps/mesh/src/api/app.ts(CORS middleware, ~L1089)packages/runtime/src/index.ts(DEFAULT_CORS_OPTIONS, ~L268)If session auth is cookie-based, a site the victim visits can issue credentialed
cross-origin requests to the gateway and read the responses (connections, tokens,
org data). The
origin.includes("localhost")check is also bypassable(
https://localhost.attacker.commatches).To Reproduce
bun run dev)curl -i -H "Origin: https://evil.example" http://localhost:3000/<any-endpoint>Access-Control-Allow-Origin: https://evil.exampletogetherwith
Access-Control-Allow-Credentials: trueExpected behavior
Only allowlisted origins (plus localhost in dev) should be reflected. Implement
the existing TODO: read an allowlist from env (e.g.
ALLOWED_ORIGINS,comma-separated, exact match), centralize the duplicated logic, and don't
reflect non-allowlisted origins while credentials are enabled.
Open questions before a PR:
or default-strict with an opt-out?
credentialsbe disabled for non-allowlisted origins, or is thegateway intended to be called credential-less from arbitrary origins?
Happy to open a PR once the default behavior is agreed.