| Attachment | Type URL (@type) | Per-route override | Build feature |
|---|---|---|---|
HTTP filter chain (http_filters) | type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors and type.googleapis.com/envoy.extensions.filters.http.cors.v3.CorsPolicy | disabled only | None |
What it does
The CORS filter handles cross-origin browser traffic: it answers OPTIONS preflight requests (those carrying access-control-request-method) directly, without going upstream, and adds access-control-* headers to responses for allowed origins. Two type URLs configure the same filter: Cors enables a permissive default policy, CorsPolicy sets an explicit one.
Minimal configuration
The fragment is an entry in http_filters, before the router:
- name: cors
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.CorsPolicy
allow_origin_string_match:
- exact: https://app.example.com
allow_methods: "GET, POST, PUT, DELETE"
allow_headers: "authorization, content-type"
expose_headers: "x-request-id"
allow_credentials: true
max_age: "3600"Fields
Cors takes no fields and enables a permissive default policy: all origins, methods and headers allowed, all headers exposed, no credentials, max_age 86400. CorsPolicy replaces those defaults entirely with:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
allow_origin_string_match | list of string matchers | Yes | — | Origins allowed to make cross-origin requests (exact, prefix, suffix, contains or safe_regex, each with optional ignore_case). Left empty, no origin matches. |
allow_methods | string | Yes | — | Comma-separated methods for access-control-allow-methods. An empty value fails to parse at startup. |
allow_headers | string | No | none | Comma-separated headers allowed in preflight; * allows all when credentials are off. mcp-session-id is always allowed. |
expose_headers | string | No | none | Comma-separated headers for access-control-expose-headers. mcp-session-id is always exposed. |
allow_credentials | bool | No | false | Send access-control-allow-credentials: true. |
max_age | string | No | unset | Preflight cache lifetime in seconds, as a string. |
filter_enabled, shadow_enabled, allow_private_network_access and forward_not_matching_preflights are unsupported and refused at startup.
Where policies attach
In Arion the policy attaches at the filter chain: CorsPolicy appears directly in http_filters and applies to every route served by that connection manager. Envoy's other attachment points — the virtual host cors field and CorsPolicy inside typed_per_filter_config — are not supported and are rejected at startup. Per route you can only switch the filter off with a FilterConfig override that sets disabled: true.
Ordering and interactions
Place CORS early in the chain — before authentication — so preflights, which browsers send without credentials, are answered instead of failing JWT checks. The filter never rejects a request itself: traffic from a disallowed origin passes through without CORS headers and the browser blocks the response. Allowed non-preflight requests gain their access-control-* headers on the response path.