Skip to content

Commit ec0319f

Browse files
committed
fix(translator): CSRF additional_origins must use host:port, not full URLs
Envoy CSRF filter calls hostAndPort() on the Origin header before matching against additional_origins, stripping the scheme. Values must be specified as host or host:port (e.g., "www.example.com" not "https://www.example.com"). This follows the same approach as kgateway: pass values directly to Envoy without transformation, and document the expected format clearly. Updated all test fixtures and documentation to use host-only values. Signed-off-by: asalvador <asalvador@newrelic.com>
1 parent e098b7f commit ec0319f

7 files changed

Lines changed: 31 additions & 24 deletions

File tree

internal/gatewayapi/testdata/securitypolicy-with-csrf.in.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ securityPolicies:
1212
csrf:
1313
additionalOrigins:
1414
- type: Exact
15-
value: https://www.example.com
15+
value: www.example.com
1616
- type: Prefix
17-
value: https://app.example
17+
value: app.example
1818
- type: Suffix
1919
value: .trusted.com
2020
- type: RegularExpression
21-
value: "https://.*\\.partner\\.com"
21+
value: ".*\\.partner\\.com$"
2222
httpRoutes:
2323
- apiVersion: gateway.networking.k8s.io/v1
2424
kind: HTTPRoute

internal/gatewayapi/testdata/securitypolicy-with-csrf.out.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,13 @@ securityPolicies:
105105
csrf:
106106
additionalOrigins:
107107
- type: Exact
108-
value: https://www.example.com
108+
value: www.example.com
109109
- type: Prefix
110-
value: https://app.example
110+
value: app.example
111111
- type: Suffix
112112
value: .trusted.com
113113
- type: RegularExpression
114-
value: https://.*\.partner\.com
114+
value: .*\.partner\.com$
115115
targetRef:
116116
group: gateway.networking.k8s.io
117117
kind: HTTPRoute
@@ -212,17 +212,17 @@ xdsIR:
212212
csrf:
213213
additionalOrigins:
214214
- distinct: false
215-
exact: https://www.example.com
215+
exact: www.example.com
216216
name: csrf
217217
- distinct: false
218218
name: csrf
219-
prefix: https://app.example
219+
prefix: app.example
220220
- distinct: false
221221
name: csrf
222222
suffix: .trusted.com
223223
- distinct: false
224224
name: csrf
225-
safeRegex: https://.*\.partner\.com
225+
safeRegex: .*\.partner\.com$
226226
readyListener:
227227
address: 0.0.0.0
228228
ipFamily: IPv4

internal/xds/translator/csrf.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@ func (*csrf) patchResources(*types.ResourceVersionTable, []*ir.HTTPRoute) error
155155
}
156156

157157
// buildXdsCSRFOrigins converts IR StringMatches to Envoy StringMatchers for CSRF origins.
158+
// Values are passed directly to Envoy without transformation. Users must provide
159+
// host:port values (not full URLs) because Envoy's CSRF filter strips the scheme
160+
// from the Origin header before matching.
158161
func buildXdsCSRFOrigins(csrf *ir.CSRF) []*matcherv3.StringMatcher {
159162
if csrf == nil {
160163
return nil

internal/xds/translator/testdata/in/xds-ir/csrf.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ http:
2222
security:
2323
csrf:
2424
additionalOrigins:
25-
- exact: https://www.example.com
26-
- prefix: https://app.example
25+
- exact: www.example.com
26+
- prefix: app.example
2727
- suffix: .trusted.com
28-
- safeRegex: https://.*\.partner\.com
28+
- safeRegex: .*\.partner\.com$
2929

internal/xds/translator/testdata/out/xds-ir/csrf.routes.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
envoy.filters.http.csrf:
1717
'@type': type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy
1818
additionalOrigins:
19-
- exact: https://www.example.com
20-
- prefix: https://app.example
19+
- exact: www.example.com
20+
- prefix: app.example
2121
- suffix: .trusted.com
2222
- safeRegex:
23-
regex: https://.*\.partner\.com
23+
regex: .*\.partner\.com$
2424
filterEnabled:
2525
defaultValue:
2626
numerator: 100

site/content/en/latest/tasks/security/csrf.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ When CSRF protection is enabled, the Envoy CSRF filter validates that the `Origi
1919
(POST, PUT, DELETE, PATCH) matches the destination or one of the configured additional origins.
2020
Non-mutating requests (GET, HEAD, OPTIONS) are not affected.
2121

22+
Note: Envoy's CSRF filter compares against the host and port of the origin only (the scheme is stripped
23+
before matching). Additional origins must be specified as `host` or `host:port` values, not full URLs.
24+
For example, use `www.example.com` instead of `https://www.example.com`.
25+
2226
The below example defines a SecurityPolicy that enables CSRF protection and allows additional origins
2327
matching `https://www.example.com` exactly and any subdomain of `trusted.com` via regex.
2428

@@ -39,9 +43,9 @@ spec:
3943
csrf:
4044
additionalOrigins:
4145
- type: Exact
42-
value: "https://www.example.com"
46+
value: "www.example.com"
4347
- type: RegularExpression
44-
value: "https://.*\\.trusted\\.com"
48+
value: ".*\\.trusted\\.com$"
4549
EOF
4650
```
4751

@@ -63,18 +67,18 @@ spec:
6367
csrf:
6468
additionalOrigins:
6569
- type: Exact
66-
value: "https://www.example.com"
70+
value: "www.example.com"
6771
- type: RegularExpression
68-
value: "https://.*\\.trusted\\.com"
72+
value: ".*\\.trusted\\.com$"
6973
```
7074
7175
{{% /tab %}}
7276
{{< /tabpane >}}
7377
7478
With this configuration:
7579
76-
- A `POST` request with `Origin: https://www.example.com` will be **allowed**.
77-
- A `POST` request with `Origin: https://app.trusted.com` will be **allowed** (matches the regex).
80+
- A `POST` request with `Origin: https://www.example.com` will be **allowed** (Envoy extracts `www.example.com` and matches the exact origin).
81+
- A `POST` request with `Origin: https://app.trusted.com` will be **allowed** (Envoy extracts `app.trusted.com` which matches the regex).
7882
- A `POST` request with `Origin: https://www.malicious.com` will be **rejected** with a `403 Forbidden`.
7983
- A `GET` request from any origin will be **allowed** (non-mutating).
8084

test/e2e/testdata/csrf-security-policy.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ spec:
2828
csrf:
2929
additionalOrigins:
3030
- type: Exact
31-
value: "https://www.example.com"
31+
value: "www.example.com"
3232
- type: Prefix
33-
value: "https://app.example"
33+
value: "app.example"
3434
- type: Suffix
3535
value: ".trusted.com"
3636
- type: RegularExpression
37-
value: "https://.*\\.partner\\.com"
37+
value: ".*\\.partner\\.com$"

0 commit comments

Comments
 (0)