Skip to content

[Bug]: Gateway CORS reflects any origin with credentials enabled #3757

Description

@Rooseveltfj

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

  1. Start the gateway (bun run dev)
  2. curl -i -H "Origin: https://evil.example" http://localhost:3000/<any-endpoint>
  3. 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:

  1. Default permissive (opt-in to strict) to avoid breaking existing deployments,
    or default-strict with an opt-out?
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions