diff --git a/CHANGELOG.md b/CHANGELOG.md
index 21fff0eeea..3c82f886b1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,26 @@
+## [v3.6.15](https://github.com/traefik/traefik/tree/v3.6.15) (2026-04-29)
+[All Commits](https://github.com/traefik/traefik/compare/v3.6.14...v3.6.15)
+
+**Bug fixes:**
+- **[acme]** Bump github.com/go-acme/lego/v4 to v4.35.2 ([#13043](https://github.com/traefik/traefik/pull/13043) @ldez)
+- **[acme]** Bump github.com/go-acme/lego/v4 to v4.35.1 ([#13027](https://github.com/traefik/traefik/pull/13027) @ldez)
+- **[middleware]** Add errorRequestHeaders option to Errors middleware ([#13034](https://github.com/traefik/traefik/pull/13034) @gndz07)
+- **[k8s/ingress-nginx]** Do not require a port for ExternalName services ([#13033](https://github.com/traefik/traefik/pull/13033) @kevinpollet)
+- **[server]** Bump github.com/vulcand/oxy to v2.1.0 ([#13046](https://github.com/traefik/traefik/pull/13046) @ldez)
+
+**Misc:**
+- Make FLAGS Make variable usable ([#13009](https://github.com/traefik/traefik/pull/13009) @twz123)
+
+## [v2.11.44](https://github.com/traefik/traefik/tree/v2.11.44) (2026-04-29)
+[All Commits](https://github.com/traefik/traefik/compare/v2.11.43...v2.11.44)
+
+**Bug fixes:**
+- **[middleware]** Add errorRequestHeaders option to Errors middleware ([#13034](https://github.com/traefik/traefik/pull/13034) @gndz07)
+- **[acme]** Bump github.com/go-acme/lego to v4.35.2 ([#13052](https://github.com/traefik/traefik/pull/13052) @mmatur)
+
+**Misc:**
+- Make FLAGS Make variable usable ([#13009](https://github.com/traefik/traefik/pull/13009) @twz123)
+
## [v3.7.0-rc.2](https://github.com/traefik/traefik/tree/v3.7.0-rc.2) (2026-04-22)
[All Commits](https://github.com/traefik/traefik/compare/v3.7.0-rc.1...v3.7.0-rc.2)
diff --git a/Makefile b/Makefile
index 24a2b6fc94..f3473d89b5 100644
--- a/Makefile
+++ b/Makefile
@@ -58,7 +58,7 @@ generate:
#? binary: Build the binary
binary: generate-webui dist
@echo SHA: $(VERSION) $(CODENAME) $(DATE)
- CGO_ENABLED=0 GOGC=${GOGC} GOOS=${GOOS} GOARCH=${GOARCH} go build ${FLAGS[*]} -ldflags "-s -w \
+ CGO_ENABLED=0 GOGC=${GOGC} GOOS=${GOOS} GOARCH=${GOARCH} go build ${FLAGS} -ldflags "-s -w \
-X github.com/traefik/traefik/v3/pkg/version.Version=$(VERSION) \
-X github.com/traefik/traefik/v3/pkg/version.Codename=$(CODENAME) \
-X github.com/traefik/traefik/v3/pkg/version.BuildDate=$(DATE)" \
diff --git a/docs/content/migrate/v3.md b/docs/content/migrate/v3.md
index 3e49bcdd41..cc0aa11666 100644
--- a/docs/content/migrate/v3.md
+++ b/docs/content/migrate/v3.md
@@ -80,6 +80,15 @@ Note: TLSOptions for `HostRegexp` matchers remains unsupported. Use wildcard `Ho
---
+## v3.6.15
+
+In `v3.6.15`, a new `errorRequestHeaders` option has been added to the Errors middleware.
+
+By default, the behavior is unchanged: all original request headers are forwarded to the error page service.
+If the error page service is in a separate trust domain, consider using `errorRequestHeaders` to restrict which headers are forwarded.
+
+Please check out the [Error Pages](../reference/routing-configuration/http/middlewares/errorpages.md#errorRequestHeaders) middleware documentation for more details.
+
## v3.6.14
### Kubernetes CRD: Chain middleware and `allowCrossNamespace`
diff --git a/docs/content/reference/dynamic-configuration/docker-labels.yml b/docs/content/reference/dynamic-configuration/docker-labels.yml
index eb525ee3b4..d57ef4bc58 100644
--- a/docs/content/reference/dynamic-configuration/docker-labels.yml
+++ b/docs/content/reference/dynamic-configuration/docker-labels.yml
@@ -30,6 +30,7 @@
- "traefik.http.middlewares.middleware08.digestauth.removeheader=true"
- "traefik.http.middlewares.middleware08.digestauth.users=foobar, foobar"
- "traefik.http.middlewares.middleware08.digestauth.usersfile=foobar"
+- "traefik.http.middlewares.middleware09.errors.errorrequestheaders=foobar, foobar"
- "traefik.http.middlewares.middleware09.errors.query=foobar"
- "traefik.http.middlewares.middleware09.errors.service=foobar"
- "traefik.http.middlewares.middleware09.errors.status=foobar, foobar"
diff --git a/docs/content/reference/dynamic-configuration/file.toml b/docs/content/reference/dynamic-configuration/file.toml
index 7707ce2b8f..f9efa7e5f0 100644
--- a/docs/content/reference/dynamic-configuration/file.toml
+++ b/docs/content/reference/dynamic-configuration/file.toml
@@ -193,6 +193,7 @@
status = ["foobar", "foobar"]
service = "foobar"
query = "foobar"
+ errorRequestHeaders = ["foobar", "foobar"]
[http.middlewares.Middleware09.errors.statusRewrites]
name0 = 42
name1 = 42
diff --git a/docs/content/reference/dynamic-configuration/file.yaml b/docs/content/reference/dynamic-configuration/file.yaml
index 929c625a43..691b618c38 100644
--- a/docs/content/reference/dynamic-configuration/file.yaml
+++ b/docs/content/reference/dynamic-configuration/file.yaml
@@ -208,6 +208,9 @@ http:
name1: 42
service: foobar
query: foobar
+ errorRequestHeaders:
+ - foobar
+ - foobar
Middleware10:
forwardAuth:
address: foobar
diff --git a/docs/content/reference/routing-configuration/http/middlewares/errorpages.md b/docs/content/reference/routing-configuration/http/middlewares/errorpages.md
index 9f95b0acd4..94a3b83887 100644
--- a/docs/content/reference/routing-configuration/http/middlewares/errorpages.md
+++ b/docs/content/reference/routing-configuration/http/middlewares/errorpages.md
@@ -129,3 +129,12 @@ The table below lists all the available variables and their associated values.
| `{status}` | The response status code. |
| `{originalStatus}` | The original response status code, if it has been modified by the `statusRewrites` option. |
| `{url}` | The [escaped](https://pkg.go.dev/net/url#QueryEscape) request URL.|
+
+### `errorRequestHeaders`
+
+Defines the list of original request headers forwarded to the error page service.
+
+By default (`errorRequestHeaders` not set), all request headers — including authentication material such as `Authorization` and `Cookie` — are forwarded.
+If the error page service is in a separate trust domain, use this option to restrict which headers cross the service boundary.
+
+Set to an explicit list to forward only those headers, or set to an empty list (`errorRequestHeaders: []`) to forward no headers.
diff --git a/docs/content/reference/routing-configuration/other-providers/file.toml b/docs/content/reference/routing-configuration/other-providers/file.toml
index 61fe202c3a..098353827e 100644
--- a/docs/content/reference/routing-configuration/other-providers/file.toml
+++ b/docs/content/reference/routing-configuration/other-providers/file.toml
@@ -209,6 +209,7 @@
status = ["foobar", "foobar"]
service = "foobar"
query = "foobar"
+ errorRequestHeaders = ["foobar", "foobar"]
[http.middlewares.Middleware10.errors.statusRewrites]
name0 = 42
name1 = 42
diff --git a/docs/content/reference/routing-configuration/other-providers/file.yaml b/docs/content/reference/routing-configuration/other-providers/file.yaml
index 21ddaeaf6c..8d2f918620 100644
--- a/docs/content/reference/routing-configuration/other-providers/file.yaml
+++ b/docs/content/reference/routing-configuration/other-providers/file.yaml
@@ -232,6 +232,9 @@ http:
name1: 42
service: foobar
query: foobar
+ errorRequestHeaders:
+ - foobar
+ - foobar
Middleware11:
forwardAuth:
address: foobar
diff --git a/go.mod b/go.mod
index 52300b37b5..94e7dff172 100644
--- a/go.mod
+++ b/go.mod
@@ -24,7 +24,7 @@ require (
github.com/docker/go-connections v0.6.0
github.com/fatih/structs v1.1.0
github.com/fsnotify/fsnotify v1.9.0
- github.com/go-acme/lego/v4 v4.35.1
+ github.com/go-acme/lego/v4 v4.35.2
github.com/go-kit/kit v0.13.0
github.com/go-kit/log v0.2.1
github.com/golang/protobuf v1.5.4
@@ -78,7 +78,7 @@ require (
github.com/unrolled/render v1.0.2
github.com/unrolled/secure v1.0.9
github.com/valyala/fasthttp v1.69.0
- github.com/vulcand/oxy/v2 v2.0.3
+ github.com/vulcand/oxy/v2 v2.1.0
github.com/vulcand/predicate v1.3.0
github.com/yuin/gopher-lua v1.1.1
go.opentelemetry.io/collector/pdata v1.41.0
@@ -148,7 +148,7 @@ require (
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect
- github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
+ github.com/HdrHistogram/hdrhistogram-go v1.2.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.4.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
@@ -245,7 +245,7 @@ require (
github.com/googleapis/gax-go/v2 v2.21.0 // indirect
github.com/gophercloud/gophercloud v1.14.1 // indirect
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 // indirect
- github.com/gravitational/trace v1.5.0 // indirect
+ github.com/gravitational/trace v1.5.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
github.com/hashicorp/cronexpr v1.1.2 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
@@ -285,7 +285,7 @@ require (
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
github.com/magiconair/properties v1.8.10 // indirect
github.com/mailgun/minheap v0.0.0-20170619185613-3dbe6c6bf55f // indirect
- github.com/mailgun/multibuf v0.1.2 // indirect
+ github.com/mailgun/multibuf v0.2.0 // indirect
github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51 // indirect
github.com/mailru/easyjson v0.9.1 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
@@ -319,7 +319,7 @@ require (
github.com/nrdcg/namesilo v0.5.0 // indirect
github.com/nrdcg/nodion v0.1.0 // indirect
github.com/nrdcg/oci-go-sdk/common/v1065 v1065.113.0 // indirect
- github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.112.0 // indirect
+ github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.113.0 // indirect
github.com/nrdcg/porkbun v0.4.0 // indirect
github.com/nrdcg/vegadns v0.3.0 // indirect
github.com/nzdjb/go-metaname v1.0.0 // indirect
@@ -427,7 +427,6 @@ replace (
github.com/abbot/go-http-auth => github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e
github.com/gorilla/mux => github.com/containous/mux v0.0.0-20250523120546-41b6ec3aed59
github.com/mailgun/minheap => github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595
- github.com/vulcand/oxy/v2 => github.com/traefik/oxy/v2 v2.0.0-20260126093803-fb11d60e0fdf
)
// ambiguous import: found package github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http in multiple modules
diff --git a/go.sum b/go.sum
index b848b6ba04..32d4100124 100644
--- a/go.sum
+++ b/go.sum
@@ -662,8 +662,9 @@ github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
-github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
+github.com/HdrHistogram/hdrhistogram-go v1.2.0 h1:XMJkDWuz6bM9Fzy7zORuVFKH7ZJY41G2q8KWhVGkNiY=
+github.com/HdrHistogram/hdrhistogram-go v1.2.0/go.mod h1:CiIeGiHSd06zjX+FypuEJ5EQ07KKtxZ+8J6hszwVQig=
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
@@ -1027,8 +1028,8 @@ github.com/go-acme/esa-20240910/v2 v2.48.0 h1:muSDyhjDTejxUGe3FTthCPCqRaEdYY9cG3
github.com/go-acme/esa-20240910/v2 v2.48.0/go.mod h1:shPb6hzc1rJL15IJBY8HQ4GZk4E8RC52+52twutEwIg=
github.com/go-acme/jdcloud-sdk-go v1.64.0 h1:AW9j5khk8tRYbpBJPxKmqdwIqgLs2Fz3HUK3hn2YXjs=
github.com/go-acme/jdcloud-sdk-go v1.64.0/go.mod h1:qc/m8HNX1Zgd7GAv2DSEinup8fwy3Ted3/VVx7LB5bU=
-github.com/go-acme/lego/v4 v4.35.1 h1:xTcEBsENs4Ek5EiNpN3JXy7W5aynf5KhJ6D/HuuhXv4=
-github.com/go-acme/lego/v4 v4.35.1/go.mod h1:E+4l5mPPg9dwhTz6JJptNLvtj94E2JDObI50QuFJd3s=
+github.com/go-acme/lego/v4 v4.35.2 h1:uVQg+KC/yj9R2g7Q9W5wDqhvQvxV5SMu5eqFVoN5xZU=
+github.com/go-acme/lego/v4 v4.35.2/go.mod h1:pX2jN5n8OphMGY1IaMjYm5DAEzguBaKRt8AvJAgJXpc=
github.com/go-acme/tencentclouddnspod v1.3.24 h1:uCSiOW1EJttcnOON+MVVyVDJguFL/Q4NIGkq1CrT9p8=
github.com/go-acme/tencentclouddnspod v1.3.24/go.mod h1:RKcB2wSoZncjBA0OEFj59s1ko1XDy+ZsAtk+9uMxUF0=
github.com/go-acme/tencentedgdeone v1.3.38 h1:5YsVl0H4A+cwtiUqR1eZbKFdr4OWfYp2KYJopifzKyQ=
@@ -1293,8 +1294,8 @@ github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
-github.com/gravitational/trace v1.5.0 h1:JbeL2HDGyzgy7G72Z2hP2gExEyA6Y2p7fCiSjyZwCJw=
-github.com/gravitational/trace v1.5.0/go.mod h1:dxezSkKm880IIDx+czWG8fq+pLnXjETBewMgN3jOBlg=
+github.com/gravitational/trace v1.5.1 h1:CdSymAjkE1VOef+lsC5x29jX9WbgI0fBtnRqeT4Fh+c=
+github.com/gravitational/trace v1.5.1/go.mod h1:sJKfJHIQ7IkG8kvYpFPEr6mj3WDEdZ0YAc7xAD8w7lw=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
@@ -1536,8 +1537,8 @@ github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
-github.com/mailgun/multibuf v0.1.2 h1:QE9kE27lK6LFZB4aYNVtUPlWVHVCT0zpgUr2uoq/+jk=
-github.com/mailgun/multibuf v0.1.2/go.mod h1:E+sUhIy69qgT6EM57kCPdUTlHnjTuxQBO/yf6af9Hes=
+github.com/mailgun/multibuf v0.2.0 h1:pGhv93r0GXBVTDu6RMlA9GUQjwwoy4yspIujtaT0AOA=
+github.com/mailgun/multibuf v0.2.0/go.mod h1:E+sUhIy69qgT6EM57kCPdUTlHnjTuxQBO/yf6af9Hes=
github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51 h1:Kg/NPZLLC3aAFr1YToMs98dbCdhootQ1hZIvZU28hAQ=
github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51/go.mod h1:RYmqHbhWwIz3z9eVmQ2rx82rulEMG0t+Q1bzfc9DYN4=
github.com/mailgun/ttlmap v0.0.0-20170619185759-c1c17f74874f h1:ZZYhg16XocqSKPGNQAe0aeweNtFxuedbwwb4fSlg7h4=
@@ -1688,8 +1689,8 @@ github.com/nrdcg/nodion v0.1.0 h1:zLKaqTn2X0aDuBHHfyA1zFgeZfiCpmu/O9DM73okavw=
github.com/nrdcg/nodion v0.1.0/go.mod h1:inbuh3neCtIWlMPZHtEpe43TmRXxHV6+hk97iCZicms=
github.com/nrdcg/oci-go-sdk/common/v1065 v1065.113.0 h1:OLlJVGHkTHBCXdTGpNn5ay4DV3gOZrVLxlUM6xBQrIM=
github.com/nrdcg/oci-go-sdk/common/v1065 v1065.113.0/go.mod h1:Gcs8GCaZXL3FdiDWgdnMxlOLEdRprJJnPYB22TX1jw8=
-github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.112.0 h1:sQ9SfyNFj4u2kStSd2ZbsU12b4nNyROK307fb3hkoPk=
-github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.112.0/go.mod h1:DaABHQaJMe64ppbXBsJPEESLxXRrbkiDfkR9JFeFowY=
+github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.113.0 h1:bveOZN6gZZjjEM1T9o1TUm8de3zePyDbfuluMpaRJCE=
+github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.113.0/go.mod h1:Ff6Cxm43tuGJHyltQwD3EXLs7kKpkxzqy6DGQcaiS/0=
github.com/nrdcg/porkbun v0.4.0 h1:rWweKlwo1PToQ3H+tEO9gPRW0wzzgmI/Ob3n2Guticw=
github.com/nrdcg/porkbun v0.4.0/go.mod h1:/QMskrHEIM0IhC/wY7iTCUgINsxdT2WcOphktJ9+Q54=
github.com/nrdcg/vegadns v0.3.0 h1:11FQMw7xVIRUWO9o5+Z/5YZhmPWlm4oxUUH3F6EVqQU=
@@ -1993,8 +1994,6 @@ github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XV
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/traefik/grpc-web v0.16.0 h1:eeUWZaFg6ZU0I9dWOYE2D5qkNzRBmXzzuRlxdltascY=
github.com/traefik/grpc-web v0.16.0/go.mod h1:2ttniSv7pTgBWIU2HZLokxRfFX3SA60c/DTmQQgVml4=
-github.com/traefik/oxy/v2 v2.0.0-20260126093803-fb11d60e0fdf h1:qOjmGqgXvycy0+tda6rWhTPulgQxnImwRrM1AROIvJ4=
-github.com/traefik/oxy/v2 v2.0.0-20260126093803-fb11d60e0fdf/go.mod h1:as06A23Znc9S/ilJpKqJ/UhO3Zu5JztlxVwQuKl+iZs=
github.com/traefik/paerser v0.2.2 h1:cpzW/ZrQrBh3mdwD/jnp6aXASiUFKOVr6ldP+keJTcQ=
github.com/traefik/paerser v0.2.2/go.mod h1:7BBDd4FANoVgaTZG+yh26jI6CA2nds7D/4VTEdIsh24=
github.com/traefik/yaegi v0.16.1 h1:f1De3DVJqIDKmnasUF6MwmWv1dSEEat0wcpXhD2On3E=
@@ -2034,6 +2033,8 @@ github.com/vinyldns/go-vinyldns v0.9.17 h1:hfPZfCaxcRBX6Gsgl42rLCeoal58/BH8kkvJS
github.com/vinyldns/go-vinyldns v0.9.17/go.mod h1:pwWhE9K/leGDOIduVhRGvQ3ecVMHWRfEnKYUTEU3gB4=
github.com/volcengine/volc-sdk-golang v1.0.242 h1:YEnYLl8mn83JCdO/X5GRDvxfxGvpUqk5j0Mj4VhwM6Y=
github.com/volcengine/volc-sdk-golang v1.0.242/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM=
+github.com/vulcand/oxy/v2 v2.1.0 h1:JnFb/qz+o96E6NEl4X6WSmNmcrlccPmCIyhAZLBVLWM=
+github.com/vulcand/oxy/v2 v2.1.0/go.mod h1:9kY0wYBlMqrgXCZTNYCwE89NYwGGdM3sSD+w59CKMhw=
github.com/vulcand/predicate v1.3.0 h1:jtNe4PHbLJ649dR7Gl+MSAzUhLGtLspAkWlSjoOiXg8=
github.com/vulcand/predicate v1.3.0/go.mod h1:opzv9MetRuMNnuoPeTSWtwzjcXsxQC00/fuWzkPTn4s=
github.com/vultr/govultr/v3 v3.31.0 h1:xSRqIQEnB3tjgpIOADWQOhOedDsqZj9qawW+mAoq7/8=
diff --git a/pkg/config/dynamic/middlewares.go b/pkg/config/dynamic/middlewares.go
index bd28f057fe..0f6666646b 100644
--- a/pkg/config/dynamic/middlewares.go
+++ b/pkg/config/dynamic/middlewares.go
@@ -271,6 +271,10 @@ type ErrorPage struct {
// The {originalStatus} variable can be used in order to insert the upstream status code in the URL.
// The {url} variable can be used in order to insert the escaped request URL.
Query string `json:"query,omitempty" toml:"query,omitempty" yaml:"query,omitempty" export:"true"`
+ // ErrorRequestHeaders defines the list of request headers forwarded to the error page service.
+ // When nil (not set), all original request headers are forwarded.
+ // Set to an empty list to forward no headers, or list specific headers to forward only those.
+ ErrorRequestHeaders []string `json:"errorRequestHeaders,omitempty" toml:"errorRequestHeaders,omitempty" yaml:"errorRequestHeaders,omitempty" export:"true"`
// NginxHeaders defines the headers to forward to the Error page service.
// NginxHeaders option is unexposed to other providers than the IngressNGINX one.
diff --git a/pkg/config/dynamic/zz_generated.deepcopy.go b/pkg/config/dynamic/zz_generated.deepcopy.go
index da6a31c35b..4ea53f9d4b 100644
--- a/pkg/config/dynamic/zz_generated.deepcopy.go
+++ b/pkg/config/dynamic/zz_generated.deepcopy.go
@@ -381,6 +381,11 @@ func (in *ErrorPage) DeepCopyInto(out *ErrorPage) {
(*out)[key] = val
}
}
+ if in.ErrorRequestHeaders != nil {
+ in, out := &in.ErrorRequestHeaders, &out.ErrorRequestHeaders
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
if in.NginxHeaders != nil {
in, out := &in.NginxHeaders, &out.NginxHeaders
*out = new(http.Header)
diff --git a/pkg/middlewares/customerrors/custom_errors.go b/pkg/middlewares/customerrors/custom_errors.go
index 6eda509759..57ca141642 100644
--- a/pkg/middlewares/customerrors/custom_errors.go
+++ b/pkg/middlewares/customerrors/custom_errors.go
@@ -38,6 +38,7 @@ type customErrors struct {
backendHandler http.Handler
httpCodeRanges types.HTTPCodeRanges
backendQuery string
+ requestHeaders []string
statusRewrites []statusRewrite
forwardNginxHeaders http.Header
}
@@ -81,6 +82,7 @@ func New(ctx context.Context, next http.Handler, config dynamic.ErrorPage, servi
backendHandler: backend,
httpCodeRanges: httpCodeRanges,
backendQuery: config.Query,
+ requestHeaders: config.ErrorRequestHeaders,
statusRewrites: statusRewrites,
forwardNginxHeaders: ptr.Deref(config.NginxHeaders, nil),
}, nil
@@ -148,6 +150,16 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return
}
+ if c.requestHeaders != nil {
+ for _, header := range c.requestHeaders {
+ if values := req.Header.Values(header); len(values) > 0 {
+ pageReq.Header[http.CanonicalHeaderKey(header)] = values
+ }
+ }
+ } else {
+ utils.CopyHeaders(pageReq.Header, req.Header)
+ }
+
if len(c.forwardNginxHeaders) > 0 {
utils.CopyHeaders(pageReq.Header, c.forwardNginxHeaders)
pageReq.Header.Set("X-Code", strconv.Itoa(code))
@@ -156,11 +168,7 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if requestID := req.Header.Get("X-Request-ID"); requestID != "" {
pageReq.Header.Set("X-Request-ID", requestID)
}
- } else {
- utils.CopyHeaders(pageReq.Header, req.Header)
- }
- if len(c.forwardNginxHeaders) > 0 {
c.backendHandler.ServeHTTP(rw, pageReq.WithContext(req.Context()))
} else {
c.backendHandler.ServeHTTP(newCodeModifier(rw, code),
diff --git a/pkg/middlewares/customerrors/custom_errors_test.go b/pkg/middlewares/customerrors/custom_errors_test.go
index ed49cf13dd..658d1c0d5d 100644
--- a/pkg/middlewares/customerrors/custom_errors_test.go
+++ b/pkg/middlewares/customerrors/custom_errors_test.go
@@ -23,6 +23,7 @@ func TestHandler(t *testing.T) {
backendCode int
backendErrorHandler http.HandlerFunc
validate func(t *testing.T, recorder *httptest.ResponseRecorder)
+ requestHeaders map[string]string
}{
{
desc: "no error",
@@ -154,6 +155,60 @@ func TestHandler(t *testing.T) {
assert.Contains(t, recorder.Body.String(), "My 503 page.")
},
},
+ {
+ desc: "forward all headers by default",
+ errorPage: &dynamic.ErrorPage{Service: "error", Query: "/test", Status: []string{"503"}},
+ requestHeaders: map[string]string{
+ "X-Request-Id": "trace-abc",
+ "Authorization": "Bearer secret",
+ },
+ backendCode: http.StatusServiceUnavailable,
+ backendErrorHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintln(w, r.Header.Get("X-Request-Id"))
+ fmt.Fprintln(w, r.Header.Get("Authorization"))
+ }),
+ validate: func(t *testing.T, recorder *httptest.ResponseRecorder) {
+ t.Helper()
+ assert.Contains(t, recorder.Body.String(), "trace-abc")
+ assert.Contains(t, recorder.Body.String(), "Bearer secret")
+ },
+ },
+ {
+ desc: "forward only allowlisted headers",
+ errorPage: &dynamic.ErrorPage{Service: "error", Query: "/test", Status: []string{"503"}, ErrorRequestHeaders: []string{"X-Request-Id"}},
+ requestHeaders: map[string]string{
+ "X-Request-Id": "trace-abc",
+ "Authorization": "Bearer secret",
+ },
+ backendCode: http.StatusServiceUnavailable,
+ backendErrorHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintln(w, r.Header.Get("X-Request-Id"))
+ fmt.Fprintln(w, r.Header.Get("Authorization"))
+ }),
+ validate: func(t *testing.T, recorder *httptest.ResponseRecorder) {
+ t.Helper()
+ assert.Contains(t, recorder.Body.String(), "trace-abc")
+ assert.NotContains(t, recorder.Body.String(), "Bearer secret")
+ },
+ },
+ {
+ desc: "forward no headers",
+ errorPage: &dynamic.ErrorPage{Service: "error", Query: "/test", Status: []string{"503"}, ErrorRequestHeaders: []string{}},
+ requestHeaders: map[string]string{
+ "X-Request-Id": "trace-abc",
+ "Authorization": "Bearer secret",
+ },
+ backendCode: http.StatusServiceUnavailable,
+ backendErrorHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintln(w, r.Header.Get("X-Request-Id"))
+ fmt.Fprintln(w, r.Header.Get("Authorization"))
+ }),
+ validate: func(t *testing.T, recorder *httptest.ResponseRecorder) {
+ t.Helper()
+ assert.NotContains(t, recorder.Body.String(), "trace-abc")
+ assert.NotContains(t, recorder.Body.String(), "Bearer secret")
+ },
+ },
{
desc: "nginx headers: backend status code preserved",
errorPage: &dynamic.ErrorPage{
@@ -253,6 +308,9 @@ func TestHandler(t *testing.T) {
require.NoError(t, err)
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost/test?foo=bar&baz=buz", nil)
+ for k, v := range test.requestHeaders {
+ req.Header.Set(k, v)
+ }
// Client like browser and curl will issue a relative HTTP request, which not have a host and scheme in the URL. But the http.NewRequest will set them automatically.
req.URL.Host = ""
diff --git a/script/gcg/traefik-bugfix.toml b/script/gcg/traefik-bugfix.toml
index 0649aadab8..58feb28035 100644
--- a/script/gcg/traefik-bugfix.toml
+++ b/script/gcg/traefik-bugfix.toml
@@ -4,11 +4,11 @@ RepositoryName = "traefik"
OutputType = "file"
FileName = "traefik_changelog.md"
-# example new bugfix v3.6.14
+# example new bugfix v3.6.15
CurrentRef = "v3.6"
-PreviousRef = "v3.6.13"
+PreviousRef = "v3.6.14"
BaseBranch = "v3.6"
-FutureCurrentRefName = "v3.6.14"
+FutureCurrentRefName = "v3.6.15"
ThresholdPreviousRef = 10000
ThresholdCurrentRef = 10000