From de3dec2654e851c0a7a7ac61b68eff130507acb9 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 26 Oct 2026 14:15:37 +0000 Subject: [PATCH 1/3] [Automated] Draft docs (agentgateway): csrf: treat Origin: null as a cross-origin request (+1 related) Signed-off-by: GitHub Action --- assets/agw-docs/pages/security/csrf.md | 6 +++++- .../docs/kubernetes/main/release-notes/release-notes.md | 1 + .../main/documentation/configuration/security/csrf.md | 7 +++++-- .../docs/standalone/main/release-notes/release-notes.md | 4 ++++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/assets/agw-docs/pages/security/csrf.md b/assets/agw-docs/pages/security/csrf.md index 87f52701e..01e957ce6 100644 --- a/assets/agw-docs/pages/security/csrf.md +++ b/assets/agw-docs/pages/security/csrf.md @@ -8,6 +8,10 @@ According to [OWASP](https://community.owasp.org/attacks/csrf), CSRF is defined To help prevent CSRF attacks, you can enable CSRF protection for your gateway or a specific route. For each route that you apply the CSRF policy to, the filter checks to make sure that a request's origin matches its destination. If the origin and destination do not match, a 403 Forbidden error code is returned. +{{< version exclude-if="1.0.x,1.1.x,1.2.x,1.3.x,1.4.x,1.5.x,1.6.x,2.2.x" >}} +For requests without a `Sec-Fetch-Site` header, the policy compares the host in the `Origin` header with the request `Host` and ignores the scheme. The policy treats an `Origin: null` header as cross-origin and rejects the request unless you add `null` to `additionalOrigins`. +{{< /version >}} + Review the following diagram to see an example CSRF request flow: ```mermaid sequenceDiagram @@ -74,7 +78,7 @@ Configure an {{< reuse "agw-docs/snippets/policy.md" >}} to enable CSRF protecti | Field | Description | |-------|-------------| | `csrf` | Enables CSRF protection for the targeted Gateway or routes. When configured, all cross-origin requests are validated. | - | `additionalOrigins` | List of additional origins that are allowed to make requests to your app beyond the same-origin requests. This is useful for trusted partners, subdomains, or CDNs. Origins cannot include wildcards. | + | `additionalOrigins` | List of additional origins that are allowed to make requests to your app beyond the same-origin requests. This is useful for trusted partners, subdomains, or CDNs. Origins cannot include wildcards.{{< version exclude-if="1.0.x,1.1.x,1.2.x,1.3.x,1.4.x,1.5.x,1.6.x,2.2.x" >}} To trust opaque origins from clients that do not send `Sec-Fetch-Site`, add `null` to this list.{{< /version >}} | {{< doc-test paths="csrf" >}} diff --git a/content/docs/kubernetes/main/release-notes/release-notes.md b/content/docs/kubernetes/main/release-notes/release-notes.md index 6d728e710..b56aebf2c 100644 --- a/content/docs/kubernetes/main/release-notes/release-notes.md +++ b/content/docs/kubernetes/main/release-notes/release-notes.md @@ -99,6 +99,7 @@ Review the release notes for agentgateway on Kubernetes. **Security** +- CSRF validation rejects `Origin: null` on requests without `Sec-Fetch-Site`, and same-origin fallback compares only the `Origin` host to the request `Host`. - Invalid `oauthTokenExchange` or `crossAppAccess` backend authentication no longer blocks the rest of your configuration from reaching the proxy. Only requests that use the invalid block fail, with HTTP `500` and the message `oauthTokenExchange configuration is invalid` or `crossAppAccess configuration is invalid`. The policy reports `Accepted: True` with the reason `PartiallyValid`. For more information, see [Debug your setup]({{< link-hextra path="/documentation/operations/debug/" >}}). **Operations** diff --git a/content/docs/standalone/main/documentation/configuration/security/csrf.md b/content/docs/standalone/main/documentation/configuration/security/csrf.md index 69f742753..2dbd74f6a 100644 --- a/content/docs/standalone/main/documentation/configuration/security/csrf.md +++ b/content/docs/standalone/main/documentation/configuration/security/csrf.md @@ -24,6 +24,8 @@ According to [OWASP](https://community.owasp.org/attacks/csrf), CSRF is defined To help prevent CSRF attacks, the CSRF policy implements a multi-layered validation approach to allow or block requests based on their properties. The policy checks that the request's origin matches its destination. If the origin and destination do not match, a 403 Forbidden error code is returned. Unlike CORS, CSRF protection works with all HTTP clients, not just browsers. +For requests without a `Sec-Fetch-Site` header, the policy compares the host in the `Origin` header with the request `Host` and ignores the scheme. The policy treats an `Origin: null` header as cross-origin and rejects the request unless you add `null` to `additionalOrigins`. + Review the following diagram to see an example CSRF request flow: ```mermaid sequenceDiagram @@ -59,7 +61,7 @@ sequenceDiagram Allowed requests are as follows. - Safe methods (`GET`, `HEAD`, `OPTIONS`) from any origin -- Same-origin requests (`Origin` matches `Host`) +- Same-origin requests, where the `Origin` host matches `Host` regardless of scheme - Requests from origins in `additionalOrigins` - Requests with `Sec-Fetch-Site: same-origin` or `Sec-Fetch-Site: none` @@ -69,6 +71,7 @@ Blocked requests, which receive a `403 Forbidden` response with the message "CSR - Cross-site requests with `Sec-Fetch-Site: cross-site` (unless trusted) - Cross-site requests where `Origin` doesn't match `Host` (unless trusted) +- Requests without `Sec-Fetch-Site` and with `Origin: null` (unless trusted) - Malformed `Origin` headers in cross-site contexts > [!NOTE] @@ -158,7 +161,7 @@ agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} The `additionalOrigins` setting is a list of trusted origins allowed to make cross-site requests. -- Format: `"scheme://host[:port]"` +- Format: `"scheme://host[:port]"`. Use `"null"` only for opaque origins from trusted clients that do not send `Sec-Fetch-Site`. - Examples: `"https://www.example.com"`, `"http://localhost:3000"` For strict CSRF protection to prevent all cross-site requests, set `additionalOrigins` to an empty list, as shown in the following route-level policy. diff --git a/content/docs/standalone/main/release-notes/release-notes.md b/content/docs/standalone/main/release-notes/release-notes.md index 4924aaaa1..8dd1e8a8e 100644 --- a/content/docs/standalone/main/release-notes/release-notes.md +++ b/content/docs/standalone/main/release-notes/release-notes.md @@ -126,6 +126,10 @@ For more information, see [Session key]({{< link-hextra path="/integrations/mcp/ - Standalone configuration reloads now track files that agentgateway reads during parsing, such as `backendTLS.root` certificate files, so later file changes are picked up without a process restart. - Metrics requests use the OpenMetrics content type by default, while browser requests use `text/plain` so browsers display metrics instead of downloading them. +**Security** + +- CSRF validation rejects `Origin: null` on requests without `Sec-Fetch-Site`, and same-origin fallback compares only the `Origin` host to the request `Host`. + ## ✨ Highlights {#v16-highlights} Version 1.6 provides many updates to existing features, including the following quick highlights. Before you upgrade, review the [breaking changes](#v16-breaking-changes), because several defaults change. From 64c1643ade1914f26373686f93023d382a70ff1c Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Mon, 26 Oct 2026 11:09:10 -0400 Subject: [PATCH 2/3] Moved release notes changes Signed-off-by: Kristin Brown --- content/docs/kubernetes/main/release-notes/release-notes.md | 1 - content/docs/standalone/main/release-notes/release-notes.md | 4 ---- 2 files changed, 5 deletions(-) diff --git a/content/docs/kubernetes/main/release-notes/release-notes.md b/content/docs/kubernetes/main/release-notes/release-notes.md index b56aebf2c..6d728e710 100644 --- a/content/docs/kubernetes/main/release-notes/release-notes.md +++ b/content/docs/kubernetes/main/release-notes/release-notes.md @@ -99,7 +99,6 @@ Review the release notes for agentgateway on Kubernetes. **Security** -- CSRF validation rejects `Origin: null` on requests without `Sec-Fetch-Site`, and same-origin fallback compares only the `Origin` host to the request `Host`. - Invalid `oauthTokenExchange` or `crossAppAccess` backend authentication no longer blocks the rest of your configuration from reaching the proxy. Only requests that use the invalid block fail, with HTTP `500` and the message `oauthTokenExchange configuration is invalid` or `crossAppAccess configuration is invalid`. The policy reports `Accepted: True` with the reason `PartiallyValid`. For more information, see [Debug your setup]({{< link-hextra path="/documentation/operations/debug/" >}}). **Operations** diff --git a/content/docs/standalone/main/release-notes/release-notes.md b/content/docs/standalone/main/release-notes/release-notes.md index 8dd1e8a8e..4924aaaa1 100644 --- a/content/docs/standalone/main/release-notes/release-notes.md +++ b/content/docs/standalone/main/release-notes/release-notes.md @@ -126,10 +126,6 @@ For more information, see [Session key]({{< link-hextra path="/integrations/mcp/ - Standalone configuration reloads now track files that agentgateway reads during parsing, such as `backendTLS.root` certificate files, so later file changes are picked up without a process restart. - Metrics requests use the OpenMetrics content type by default, while browser requests use `text/plain` so browsers display metrics instead of downloading them. -**Security** - -- CSRF validation rejects `Origin: null` on requests without `Sec-Fetch-Site`, and same-origin fallback compares only the `Origin` host to the request `Host`. - ## ✨ Highlights {#v16-highlights} Version 1.6 provides many updates to existing features, including the following quick highlights. Before you upgrade, review the [breaking changes](#v16-breaking-changes), because several defaults change. From 9d59db92d001445a9cceb7cc08c0a837f4f3a0b3 Mon Sep 17 00:00:00 2001 From: Art Berger Date: Mon, 26 Oct 2026 12:37:29 -0400 Subject: [PATCH 3/3] docs: tighten CSRF origin-match and null-origin wording - The Origin check compares host and port (URI authority), not the host alone. Verified live on b75bb313: https://localhost vs Host localhost:4301 is rejected, and https://localhost:4301 is allowed. - additionalOrigins: null exempts Origin: null whether or not the request sends Sec-Fetch-Site (csrf.rs is_request_exempt). - Gate the asset text with upstream version tokens only. Signed-off-by: Art Berger --- assets/agw-docs/pages/security/csrf.md | 6 +++--- .../main/documentation/configuration/security/csrf.md | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/assets/agw-docs/pages/security/csrf.md b/assets/agw-docs/pages/security/csrf.md index 01e957ce6..404d5b985 100644 --- a/assets/agw-docs/pages/security/csrf.md +++ b/assets/agw-docs/pages/security/csrf.md @@ -8,8 +8,8 @@ According to [OWASP](https://community.owasp.org/attacks/csrf), CSRF is defined To help prevent CSRF attacks, you can enable CSRF protection for your gateway or a specific route. For each route that you apply the CSRF policy to, the filter checks to make sure that a request's origin matches its destination. If the origin and destination do not match, a 403 Forbidden error code is returned. -{{< version exclude-if="1.0.x,1.1.x,1.2.x,1.3.x,1.4.x,1.5.x,1.6.x,2.2.x" >}} -For requests without a `Sec-Fetch-Site` header, the policy compares the host in the `Origin` header with the request `Host` and ignores the scheme. The policy treats an `Origin: null` header as cross-origin and rejects the request unless you add `null` to `additionalOrigins`. +{{< version exclude-if="1.6.x,1.5.x,1.4.x,1.3.x,1.2.x,1.1.x,1.0.x" >}} +For requests without a `Sec-Fetch-Site` header, the policy compares the host and port in the `Origin` header with the request `Host` header. The policy ignores the scheme, so the origin `https://www.example.com` matches a plain HTTP request to `www.example.com`. The policy treats an `Origin: null` header as a cross-origin request, and rejects it unless `additionalOrigins` contains `null`. {{< /version >}} Review the following diagram to see an example CSRF request flow: @@ -78,7 +78,7 @@ Configure an {{< reuse "agw-docs/snippets/policy.md" >}} to enable CSRF protecti | Field | Description | |-------|-------------| | `csrf` | Enables CSRF protection for the targeted Gateway or routes. When configured, all cross-origin requests are validated. | - | `additionalOrigins` | List of additional origins that are allowed to make requests to your app beyond the same-origin requests. This is useful for trusted partners, subdomains, or CDNs. Origins cannot include wildcards.{{< version exclude-if="1.0.x,1.1.x,1.2.x,1.3.x,1.4.x,1.5.x,1.6.x,2.2.x" >}} To trust opaque origins from clients that do not send `Sec-Fetch-Site`, add `null` to this list.{{< /version >}} | + | `additionalOrigins` | List of additional origins that are allowed to make requests to your app beyond the same-origin requests. This is useful for trusted partners, subdomains, or CDNs. Origins cannot include wildcards.{{< version exclude-if="1.6.x,1.5.x,1.4.x,1.3.x,1.2.x,1.1.x,1.0.x" >}} To allow requests that send an `Origin: null` header, add `null` to this list.{{< /version >}} | {{< doc-test paths="csrf" >}} diff --git a/content/docs/standalone/main/documentation/configuration/security/csrf.md b/content/docs/standalone/main/documentation/configuration/security/csrf.md index 2dbd74f6a..d0742b639 100644 --- a/content/docs/standalone/main/documentation/configuration/security/csrf.md +++ b/content/docs/standalone/main/documentation/configuration/security/csrf.md @@ -24,7 +24,7 @@ According to [OWASP](https://community.owasp.org/attacks/csrf), CSRF is defined To help prevent CSRF attacks, the CSRF policy implements a multi-layered validation approach to allow or block requests based on their properties. The policy checks that the request's origin matches its destination. If the origin and destination do not match, a 403 Forbidden error code is returned. Unlike CORS, CSRF protection works with all HTTP clients, not just browsers. -For requests without a `Sec-Fetch-Site` header, the policy compares the host in the `Origin` header with the request `Host` and ignores the scheme. The policy treats an `Origin: null` header as cross-origin and rejects the request unless you add `null` to `additionalOrigins`. +For requests without a `Sec-Fetch-Site` header, the policy compares the host and port in the `Origin` header with the request `Host` header. The policy ignores the scheme, so the origin `https://www.example.com` matches a plain HTTP request to `www.example.com`. The policy treats an `Origin: null` header as a cross-origin request, and rejects it unless `additionalOrigins` contains `null`. Review the following diagram to see an example CSRF request flow: ```mermaid @@ -61,7 +61,7 @@ sequenceDiagram Allowed requests are as follows. - Safe methods (`GET`, `HEAD`, `OPTIONS`) from any origin -- Same-origin requests, where the `Origin` host matches `Host` regardless of scheme +- Same-origin requests, where the host and port in `Origin` match `Host`, regardless of scheme - Requests from origins in `additionalOrigins` - Requests with `Sec-Fetch-Site: same-origin` or `Sec-Fetch-Site: none` @@ -161,7 +161,7 @@ agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} The `additionalOrigins` setting is a list of trusted origins allowed to make cross-site requests. -- Format: `"scheme://host[:port]"`. Use `"null"` only for opaque origins from trusted clients that do not send `Sec-Fetch-Site`. +- Format: `"scheme://host[:port]"`. To allow requests that send an `Origin: null` header, add `"null"`. - Examples: `"https://www.example.com"`, `"http://localhost:3000"` For strict CSRF protection to prevent all cross-site requests, set `additionalOrigins` to an empty list, as shown in the following route-level policy.