From fc671859879eb7c2fcae34d771f158a5da920a36 Mon Sep 17 00:00:00 2001 From: Barbara Soraggi <108243062+bpsoraggi@users.noreply.github.com> Date: Tue, 13 Jan 2026 09:08:04 +0000 Subject: [PATCH 1/4] Replace markdown-include dependency with mkdocs-include-markdown-plugin --- docs/content/getting-started/concepts.md | 2 +- docs/content/getting-started/configuration-overview.md | 2 +- docs/content/getting-started/faq.md | 2 +- docs/content/getting-started/install-traefik.md | 2 +- docs/content/getting-started/quick-start-with-kubernetes.md | 2 +- docs/content/getting-started/quick-start.md | 2 +- docs/content/https/acme.md | 2 +- docs/content/https/overview.md | 2 +- docs/content/https/tls.md | 2 +- docs/content/middlewares/http/basicauth.md | 2 +- docs/content/middlewares/http/forwardauth.md | 2 +- docs/content/middlewares/http/headers.md | 2 +- docs/content/middlewares/http/overview.md | 2 +- docs/content/middlewares/http/redirectregex.md | 2 +- docs/content/middlewares/http/stripprefix.md | 2 +- docs/content/middlewares/overview.md | 2 +- docs/content/observability/access-logs.md | 2 +- docs/content/observability/logs.md | 2 +- docs/content/operations/api.md | 2 +- docs/content/operations/dashboard.md | 2 +- docs/content/plugins/index.md | 2 +- docs/content/providers/docker.md | 2 +- docs/content/providers/file.md | 2 +- docs/content/providers/kubernetes-crd.md | 2 +- docs/content/providers/kubernetes-gateway.md | 2 +- docs/content/providers/kubernetes-ingress.md | 2 +- docs/content/providers/overview.md | 2 +- .../reference/dynamic-configuration/kubernetes-crd.md | 2 +- .../reference/dynamic-configuration/kubernetes-gateway.md | 2 +- docs/content/routing/entrypoints.md | 2 +- docs/content/routing/overview.md | 2 +- docs/content/routing/providers/kubernetes-crd.md | 2 +- docs/content/routing/providers/kubernetes-gateway.md | 2 +- docs/content/routing/providers/kubernetes-ingress.md | 2 +- docs/content/routing/routers/index.md | 2 +- docs/content/routing/services/index.md | 2 +- docs/content/user-guides/docker-compose/acme-dns/index.md | 2 +- docs/content/user-guides/docker-compose/acme-tls/index.md | 2 +- .../user-guides/docker-compose/basic-example/index.md | 2 +- docs/mkdocs.yml | 5 ++--- docs/requirements.txt | 4 ++-- 41 files changed, 43 insertions(+), 44 deletions(-) diff --git a/docs/content/getting-started/concepts.md b/docs/content/getting-started/concepts.md index 21e1817f7f..a2bd774f86 100644 --- a/docs/content/getting-started/concepts.md +++ b/docs/content/getting-started/concepts.md @@ -57,4 +57,4 @@ You no longer need to create and synchronize configuration files cluttered with Traefik is able to use your cluster API to discover the services and read the attached information. In Traefik, these connectors are called [providers](../providers/overview.md "Link to overview about Traefik providers") because they *provide* the configuration to Traefik. -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/getting-started/configuration-overview.md b/docs/content/getting-started/configuration-overview.md index 734e29871e..fd7224bf5d 100644 --- a/docs/content/getting-started/configuration-overview.md +++ b/docs/content/getting-started/configuration-overview.md @@ -94,4 +94,4 @@ All the configuration options are documented in their related section. You can browse the available features in the menu, the [providers](../providers/overview.md), or the [routing section](../routing/overview.md) to see them in action. -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/getting-started/faq.md b/docs/content/getting-started/faq.md index 66f2d4d046..9b6f69b577 100644 --- a/docs/content/getting-started/faq.md +++ b/docs/content/getting-started/faq.md @@ -252,4 +252,4 @@ In which case, you should make sure your infrastructure is properly set up for a LEGO_DISABLE_CNAME_SUPPORT=true ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/getting-started/install-traefik.md b/docs/content/getting-started/install-traefik.md index 705b335c1c..f052460cab 100644 --- a/docs/content/getting-started/install-traefik.md +++ b/docs/content/getting-started/install-traefik.md @@ -144,4 +144,4 @@ And run it: All the details are available in the [Contributing Guide](../contributing/building-testing.md) -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/getting-started/quick-start-with-kubernetes.md b/docs/content/getting-started/quick-start-with-kubernetes.md index ba94918e9b..5cb0714617 100644 --- a/docs/content/getting-started/quick-start-with-kubernetes.md +++ b/docs/content/getting-started/quick-start-with-kubernetes.md @@ -334,4 +334,4 @@ curl -v http://localhost/ - Use [IngressRoute CRD](../providers/kubernetes-crd.md) - Protect [ingresses with TLS](../routing/providers/kubernetes-ingress.md#enabling-tls-via-annotations) -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/getting-started/quick-start.md b/docs/content/getting-started/quick-start.md index 90db5a165d..99a3566664 100644 --- a/docs/content/getting-started/quick-start.md +++ b/docs/content/getting-started/quick-start.md @@ -121,4 +121,4 @@ IP: 172.27.0.4 Now that you have a basic understanding of how Traefik can automatically create the routes to your services and load balance them, it is time to dive into [the user guides](../../user-guides/docker-compose/basic-example/ "Link to the user guides") and [the documentation](/ "Link to the docs landing page") and let Traefik work for you! -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/https/acme.md b/docs/content/https/acme.md index eb9245650c..68fe584e57 100644 --- a/docs/content/https/acme.md +++ b/docs/content/https/acme.md @@ -797,4 +797,4 @@ If Let's Encrypt is not reachable, the following certificates will apply: !!! important For new (sub)domains which need Let's Encrypt authentication, the default Traefik certificate will be used until Traefik is restarted. -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/https/overview.md b/docs/content/https/overview.md index 9261d0db8d..ae07504d92 100644 --- a/docs/content/https/overview.md +++ b/docs/content/https/overview.md @@ -20,4 +20,4 @@ That is to say, how to obtain [TLS certificates](./tls.md#certificates-definitio either through a definition in the dynamic configuration, or through [Let's Encrypt](./acme.md) (ACME). And how to configure [TLS options](./tls.md#tls-options), and [certificates stores](./tls.md#certificates-stores). -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/https/tls.md b/docs/content/https/tls.md index 2d8178e6d3..4596095d76 100644 --- a/docs/content/https/tls.md +++ b/docs/content/https/tls.md @@ -561,4 +561,4 @@ spec: clientAuthType: RequireAndVerifyClientCert ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/middlewares/http/basicauth.md b/docs/content/middlewares/http/basicauth.md index 9a6b3c5799..08ab3dc42e 100644 --- a/docs/content/middlewares/http/basicauth.md +++ b/docs/content/middlewares/http/basicauth.md @@ -404,4 +404,4 @@ http: [http.middlewares.test-auth.basicAuth] removeHeader = true ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/middlewares/http/forwardauth.md b/docs/content/middlewares/http/forwardauth.md index 8e8485c9e9..1b2ae3eb22 100644 --- a/docs/content/middlewares/http/forwardauth.md +++ b/docs/content/middlewares/http/forwardauth.md @@ -637,4 +637,4 @@ http: [http.middlewares.test-auth.forwardAuth.tls] insecureSkipVerify: true ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/middlewares/http/headers.md b/docs/content/middlewares/http/headers.md index 3af8f36a76..b72ba91304 100644 --- a/docs/content/middlewares/http/headers.md +++ b/docs/content/middlewares/http/headers.md @@ -480,4 +480,4 @@ Set `isDevelopment` to `true` when developing to mitigate the unwanted effects o Usually testing takes place using HTTP, not HTTPS, and on `localhost`, not your production domain. If you would like your development environment to mimic production with complete Host blocking, SSL redirects, and STS headers, leave this as `false`. -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/middlewares/http/overview.md b/docs/content/middlewares/http/overview.md index 412f947608..3f7a63a045 100644 --- a/docs/content/middlewares/http/overview.md +++ b/docs/content/middlewares/http/overview.md @@ -158,4 +158,4 @@ http: Please take a look at the community-contributed plugins in the [plugin catalog](https://plugins.traefik.io/plugins). -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/middlewares/http/redirectregex.md b/docs/content/middlewares/http/redirectregex.md index e10af16fd9..06d27e0bc7 100644 --- a/docs/content/middlewares/http/redirectregex.md +++ b/docs/content/middlewares/http/redirectregex.md @@ -100,4 +100,4 @@ The `replacement` option defines how to modify the URL to have the new target UR Care should be taken when defining replacement expand variables: `$1x` is equivalent to `${1x}`, not `${1}x` (see [Regexp.Expand](https://golang.org/pkg/regexp/#Regexp.Expand)), so use `${1}` syntax. -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/middlewares/http/stripprefix.md b/docs/content/middlewares/http/stripprefix.md index 35bb527a94..185403dcfa 100644 --- a/docs/content/middlewares/http/stripprefix.md +++ b/docs/content/middlewares/http/stripprefix.md @@ -171,4 +171,4 @@ http: forceSlash = false ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/middlewares/overview.md b/docs/content/middlewares/overview.md index de799e8428..5db9e6dc3c 100644 --- a/docs/content/middlewares/overview.md +++ b/docs/content/middlewares/overview.md @@ -130,4 +130,4 @@ A list of HTTP middlewares can be found [here](http/overview.md). A list of TCP middlewares can be found [here](tcp/overview.md). -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/observability/access-logs.md b/docs/content/observability/access-logs.md index fdac4550ed..4bbd5df0f7 100644 --- a/docs/content/observability/access-logs.md +++ b/docs/content/observability/access-logs.md @@ -281,4 +281,4 @@ services: - /var/run/docker.sock:/var/run/docker.sock ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/observability/logs.md b/docs/content/observability/logs.md index f350c5f674..77c1540d7d 100644 --- a/docs/content/observability/logs.md +++ b/docs/content/observability/logs.md @@ -90,4 +90,4 @@ This allows the logs to be rotated and processed by an external program, such as !!! warning This does not work on Windows due to the lack of USR signals. -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/operations/api.md b/docs/content/operations/api.md index 16717a8bcc..f895a05c2d 100644 --- a/docs/content/operations/api.md +++ b/docs/content/operations/api.md @@ -175,4 +175,4 @@ All the following endpoints must be accessed with a `GET` HTTP request. | `/debug/pprof/symbol` | See the [pprof Symbol](https://golang.org/pkg/net/http/pprof/#Symbol) Go documentation. | | `/debug/pprof/trace` | See the [pprof Trace](https://golang.org/pkg/net/http/pprof/#Trace) Go documentation. | -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/operations/dashboard.md b/docs/content/operations/dashboard.md index 353470cdf3..ceae503d21 100644 --- a/docs/content/operations/dashboard.md +++ b/docs/content/operations/dashboard.md @@ -132,4 +132,4 @@ api: --api.dashboard=false ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/plugins/index.md b/docs/content/plugins/index.md index 9cd3662f89..b3172a9a85 100644 --- a/docs/content/plugins/index.md +++ b/docs/content/plugins/index.md @@ -31,4 +31,4 @@ The experience of implementing a Traefik plugin is comparable to writing a web b To learn more about Traefik plugin creation, please refer to the [developer documentation](https://plugins.traefik.io/create). -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/providers/docker.md b/docs/content/providers/docker.md index c1cadd86b8..a06e3f1113 100644 --- a/docs/content/providers/docker.md +++ b/docs/content/providers/docker.md @@ -764,4 +764,4 @@ providers: --providers.docker.allowEmptyServices=true ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/providers/file.md b/docs/content/providers/file.md index 8abce45d69..afffcc2009 100644 --- a/docs/content/providers/file.md +++ b/docs/content/providers/file.md @@ -292,4 +292,4 @@ To illustrate, it is possible to easily define multiple routers, services, and T {{ end }} ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/providers/kubernetes-crd.md b/docs/content/providers/kubernetes-crd.md index 9c9707dedd..daa6fe5543 100644 --- a/docs/content/providers/kubernetes-crd.md +++ b/docs/content/providers/kubernetes-crd.md @@ -345,4 +345,4 @@ providers: For additional information, refer to the [full example](../user-guides/crd-acme/index.md) with Let's Encrypt. -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/providers/kubernetes-gateway.md b/docs/content/providers/kubernetes-gateway.md index a435d563a3..a2de88f5eb 100644 --- a/docs/content/providers/kubernetes-gateway.md +++ b/docs/content/providers/kubernetes-gateway.md @@ -269,4 +269,4 @@ providers: --providers.kubernetesgateway.throttleDuration=10s ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/providers/kubernetes-ingress.md b/docs/content/providers/kubernetes-ingress.md index f9fcd7e614..ab62b5725c 100644 --- a/docs/content/providers/kubernetes-ingress.md +++ b/docs/content/providers/kubernetes-ingress.md @@ -504,4 +504,4 @@ providers: To learn more about the various aspects of the Ingress specification that Traefik supports, many examples of Ingresses definitions are located in the test [examples](https://github.com/traefik/traefik/tree/v2.11/pkg/provider/kubernetes/ingress/fixtures) of the Traefik repository. -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/providers/overview.md b/docs/content/providers/overview.md index ced9ff5abd..d5a20da8a6 100644 --- a/docs/content/providers/overview.md +++ b/docs/content/providers/overview.md @@ -233,4 +233,4 @@ List of providers that support constraints: - [Kubernetes Ingress](./kubernetes-ingress.md#labelselector) - [Kubernetes Gateway](./kubernetes-gateway.md#labelselector) -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/reference/dynamic-configuration/kubernetes-crd.md b/docs/content/reference/dynamic-configuration/kubernetes-crd.md index c171ec5d3c..bdfe5a6ccd 100644 --- a/docs/content/reference/dynamic-configuration/kubernetes-crd.md +++ b/docs/content/reference/dynamic-configuration/kubernetes-crd.md @@ -36,4 +36,4 @@ Dynamic configuration with Kubernetes Custom Resource --8<-- "content/reference/dynamic-configuration/kubernetes-crd-rbac.yml" ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/reference/dynamic-configuration/kubernetes-gateway.md b/docs/content/reference/dynamic-configuration/kubernetes-gateway.md index 476dd2b47e..7ec024bdd2 100644 --- a/docs/content/reference/dynamic-configuration/kubernetes-gateway.md +++ b/docs/content/reference/dynamic-configuration/kubernetes-gateway.md @@ -30,4 +30,4 @@ Dynamic configuration with Kubernetes Gateway provider. --8<-- "content/reference/dynamic-configuration/kubernetes-gateway-rbac.yml" ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/routing/entrypoints.md b/docs/content/routing/entrypoints.md index 253d191001..02ad3d79de 100644 --- a/docs/content/routing/entrypoints.md +++ b/docs/content/routing/entrypoints.md @@ -1441,4 +1441,4 @@ entryPoints: --entryPoints.foo.udp.timeout=10s ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/routing/overview.md b/docs/content/routing/overview.md index aceb335fe4..540b87453b 100644 --- a/docs/content/routing/overview.md +++ b/docs/content/routing/overview.md @@ -412,4 +412,4 @@ serversTransport: --serversTransport.forwardingTimeouts.idleConnTimeout=1s ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/routing/providers/kubernetes-crd.md b/docs/content/routing/providers/kubernetes-crd.md index cf168ff91f..aba8fa019b 100644 --- a/docs/content/routing/providers/kubernetes-crd.md +++ b/docs/content/routing/providers/kubernetes-crd.md @@ -1904,4 +1904,4 @@ If the ServersTransport CRD is defined in another provider the cross-provider fo Also see the [full example](../../user-guides/crd-acme/index.md) with Let's Encrypt. -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/routing/providers/kubernetes-gateway.md b/docs/content/routing/providers/kubernetes-gateway.md index e07a347ed8..af9900dd2f 100644 --- a/docs/content/routing/providers/kubernetes-gateway.md +++ b/docs/content/routing/providers/kubernetes-gateway.md @@ -355,4 +355,4 @@ Kubernetes cluster before creating `TLSRoute` objects. | [11] | `group` | Group is the group of the referent. Only `traefik.io`, `traefik.containo.us` and `gateway.networking.k8s.io` values are supported. | | [12] | `kind` | Kind is kind of the referent. Only `TraefikService` and `Service` values are supported. | -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/routing/providers/kubernetes-ingress.md b/docs/content/routing/providers/kubernetes-ingress.md index 57d38892da..85fa482a44 100644 --- a/docs/content/routing/providers/kubernetes-ingress.md +++ b/docs/content/routing/providers/kubernetes-ingress.md @@ -969,4 +969,4 @@ This will allow users to create a "default router" that will match all unmatched To do this, use the `traefik.ingress.kubernetes.io/router.priority` annotation (as seen in [Annotations on Ingress](#on-ingress)) on your ingresses accordingly. -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/routing/routers/index.md b/docs/content/routing/routers/index.md index bec2ac6321..6aec7a06a7 100644 --- a/docs/content/routing/routers/index.md +++ b/docs/content/routing/routers/index.md @@ -1349,4 +1349,4 @@ Services are the target for the router. !!! important "UDP routers can only target UDP services (and not HTTP or TCP services)." -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/routing/services/index.md b/docs/content/routing/services/index.md index 55e3572825..3480b323b5 100644 --- a/docs/content/routing/services/index.md +++ b/docs/content/routing/services/index.md @@ -1646,4 +1646,4 @@ udp: address = "private-ip-server-2:8080/" ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/user-guides/docker-compose/acme-dns/index.md b/docs/content/user-guides/docker-compose/acme-dns/index.md index 78f25f8d47..eb6178d82c 100644 --- a/docs/content/user-guides/docker-compose/acme-dns/index.md +++ b/docs/content/user-guides/docker-compose/acme-dns/index.md @@ -187,4 +187,4 @@ environment: - "OVH_CONSUMER_KEY_FILE=/run/secrets/ovh_consumer_key" ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/user-guides/docker-compose/acme-tls/index.md b/docs/content/user-guides/docker-compose/acme-tls/index.md index 382244c625..ed4f7e6f68 100644 --- a/docs/content/user-guides/docker-compose/acme-tls/index.md +++ b/docs/content/user-guides/docker-compose/acme-tls/index.md @@ -83,4 +83,4 @@ labels: - "traefik.http.routers.whoami.tls.certresolver=myresolver" ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/content/user-guides/docker-compose/basic-example/index.md b/docs/content/user-guides/docker-compose/basic-example/index.md index 4b5e33cd55..a95de4798b 100644 --- a/docs/content/user-guides/docker-compose/basic-example/index.md +++ b/docs/content/user-guides/docker-compose/basic-example/index.md @@ -133,4 +133,4 @@ whoami: - "traefik.http.routers.whoami.entrypoints=web" ``` -{!traefik-for-business-applications.md!} +{% include-markdown "includes/traefik-for-business-applications.md" %} diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 9e6fe7d3cb..71d83858f9 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -39,6 +39,8 @@ plugins: - exclude: glob: - "**/include-*.md" + - include-markdown: + encoding: utf-8 # https://squidfunk.github.io/mkdocs-material/extensions/admonition/ # https://facelessuser.github.io/pymdown-extensions/ @@ -56,9 +58,6 @@ markdown_extensions: - pymdownx.tasklist - pymdownx.snippets: check_paths: true - - markdown_include.include: - base_path: content/includes/ - encoding: utf-8 - toc: permalink: true diff --git a/docs/requirements.txt b/docs/requirements.txt index 68126a411d..1eef672df3 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,5 +1,5 @@ -markdown-include==0.5.1 -mkdocs==1.2.4 +mkdocs==1.4.3 +mkdocs-include-markdown-plugin==7.2.0 mkdocs-exclude==1.0.2 mkdocs-traefiklabs>=100.0.7 From ee265a850921c90610beb36eb5704e85aeb2cd7c Mon Sep 17 00:00:00 2001 From: Sheddy Date: Tue, 13 Jan 2026 11:16:05 +0100 Subject: [PATCH 2/4] Add Scarf Analytics to documentation --- docs/content/assets/js/extra.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/content/assets/js/extra.js b/docs/content/assets/js/extra.js index eb0cc12ffc..be5a621051 100644 --- a/docs/content/assets/js/extra.js +++ b/docs/content/assets/js/extra.js @@ -1,4 +1,14 @@ /* Highlight */ (function(hljs) { hljs.initHighlightingOnLoad(); -})(hljs); \ No newline at end of file +})(hljs); + +/* Scarf Analytics - cookieless, anonymous company-level intelligence */ +(function() { + var img = document.createElement('img'); + img.src = 'https://static.scarf.sh/a.png?x-pxid=1a49232a-b165-4015-8ed2-a1092f1f0d83'; + img.referrerPolicy = 'no-referrer-when-downgrade'; + img.loading = 'eager'; + img.style.cssText = 'visibility:hidden;position:absolute;width:1px;height:1px;'; + document.body.appendChild(img); +})(); \ No newline at end of file From adf47fba316be4fa639ad980e079e5ecbc6b0e33 Mon Sep 17 00:00:00 2001 From: "Gina A." <70909035+gndz07@users.noreply.github.com> Date: Wed, 14 Jan 2026 10:16:04 +0100 Subject: [PATCH 3/4] Make encoded character options opt-in --- cmd/traefik/traefik.go | 8 +- docs/content/migration/v2.md | 27 +++++ .../reference/static-configuration/cli-ref.md | 14 +-- .../reference/static-configuration/env-ref.md | 14 +-- docs/content/routing/entrypoints.md | 105 +++++++++--------- docs/content/security/request-path.md | 23 ++-- .../fixtures/simple_encoded_chars.toml | 10 +- integration/fixtures/websocket/config.toml | 2 - integration/simple_test.go | 12 ++ pkg/config/dynamic/http_config.go | 16 +-- pkg/config/dynamic/zz_generated.deepcopy.go | 6 +- pkg/config/static/entrypoints.go | 10 ++ pkg/server/aggregator.go | 2 +- pkg/server/router/deny.go | 19 ---- pkg/server/router/deny_test.go | 36 ------ pkg/server/router/router.go | 13 +-- pkg/server/router/router_test.go | 27 +---- pkg/server/server_entrypoint_tcp.go | 20 ++++ pkg/server/server_entrypoint_tcp_test.go | 36 ++++++ 19 files changed, 221 insertions(+), 179 deletions(-) diff --git a/cmd/traefik/traefik.go b/cmd/traefik/traefik.go index 7900bb21f7..1a4de5a39c 100644 --- a/cmd/traefik/traefik.go +++ b/cmd/traefik/traefik.go @@ -87,10 +87,10 @@ Complete documentation is available at https://traefik.io`, func runCmd(staticConfiguration *static.Configuration) error { configureLogging(staticConfiguration) - // Display warning to advertise for new behavior of rejecting encoded characters in the request path. - // Deprecated: this has to be removed in the next minor/major version. - log.WithoutContext().Warnf("Starting with v2.11.32, Traefik now rejects some encoded characters in the request path by default. " + - "Refer to the documentation for more details: https://doc.traefik.io/traefik/v2.11/migration/v2/#encoded-characters-in-request-path") + log.WithoutContext().Warn("Traefik can reject some encoded characters in the request path." + + "When your backend is not fully compliant with [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986)," + + "it is recommended to set these options to `false` to avoid split-view situation." + + "Refer to the documentation for more details: https://doc.traefik.io/traefik/v2.11/migration/v2/#encoded-characters-configuration-default-values") http.DefaultTransport.(*http.Transport).Proxy = http.ProxyFromEnvironment diff --git a/docs/content/migration/v2.md b/docs/content/migration/v2.md index a7fa96ffd3..325e2ac3b2 100644 --- a/docs/content/migration/v2.md +++ b/docs/content/migration/v2.md @@ -737,3 +737,30 @@ Note: This check is not done against query parameters, but only against the request path as defined in [RFC3986 section-3](https://datatracker.ietf.org/doc/html/rfc3986#section-3). Please check out the entrypoint [encodedCharacters option](../routing/entrypoints.md#encoded-characters) documentation for more details. + +## v2.11.35 + +### Encoded Characters Configuration Default Values + +Since `v2.11.35`, the options for encoded characters now have a `true` default value. +This means that Traefik will not reject requests with a path containing a specific set of encoded characters by default. +It is now up to the users to configure the security hardening of encoded characters. + +Here is the list of the encoded characters that can be configured to `false` to disallow them: + +| Encoded Character | Character | Config options | Default value | +|-------------------|-------------------------|--------------------------------------------------------------------------------------|---------------| +| `%2f` or `%2F` | `/` (slash) | `entryPoints.`
`.http.encodedCharacters`
`.allowEncodedSlash` | `true` | +| `%5c` or `%5C` | `\` (backslash) | `entryPoints..`
`.http.encodedCharacters`
`.allowEncodedBackSlash` | `true` | +| `%00` | `NULL` (null character) | `entryPoints..`
`.http.encodedCharacters`
`.allowEncodedNullCharacter` | `true` | +| `%3b` or `%3B` | `;` (semicolon) | `entryPoints..`
`.http.encodedCharacters`
`.allowEncodedSemicolon` | `true` | +| `%25` | `%` (percent) | `entryPoints..`
`.http.encodedCharacters`
`.allowEncodedPercent` | `true` | +| `%3f` or `%3F` | `?` (question mark) | `entryPoints..`
`.http.encodedCharacters`
`.allowEncodedQuestionMark` | `true` | +| `%23` | `#` (hash) | `entryPoints..`
`.http.encodedCharacters`
`.allowEncodedHash` | `true` | + +Note: This check is not done against query parameters, +but only against the request path as defined +in [RFC3986 section-3](https://datatracker.ietf.org/doc/html/rfc3986#section-3). + +Please check out the entrypoint [encodedCharacters option](../routing/entrypoints.md#encoded-characters) documentation +for more details. diff --git a/docs/content/reference/static-configuration/cli-ref.md b/docs/content/reference/static-configuration/cli-ref.md index b9fd73d712..cec0dafd3d 100644 --- a/docs/content/reference/static-configuration/cli-ref.md +++ b/docs/content/reference/static-configuration/cli-ref.md @@ -124,25 +124,25 @@ Trust only forwarded headers from selected IPs. HTTP configuration. `--entrypoints..http.encodedcharacters.allowencodedbackslash`: -Defines whether requests with encoded back slash characters in the path are allowed. (Default: ```false```) +Defines whether requests with encoded back slash characters in the path are allowed. (Default: ```true```) `--entrypoints..http.encodedcharacters.allowencodedhash`: -Defines whether requests with encoded hash characters in the path are allowed. (Default: ```false```) +Defines whether requests with encoded hash characters in the path are allowed. (Default: ```true```) `--entrypoints..http.encodedcharacters.allowencodednullcharacter`: -Defines whether requests with encoded null characters in the path are allowed. (Default: ```false```) +Defines whether requests with encoded null characters in the path are allowed. (Default: ```true```) `--entrypoints..http.encodedcharacters.allowencodedpercent`: -Defines whether requests with encoded percent characters in the path are allowed. (Default: ```false```) +Defines whether requests with encoded percent characters in the path are allowed. (Default: ```true```) `--entrypoints..http.encodedcharacters.allowencodedquestionmark`: -Defines whether requests with encoded question mark characters in the path are allowed. (Default: ```false```) +Defines whether requests with encoded question mark characters in the path are allowed. (Default: ```true```) `--entrypoints..http.encodedcharacters.allowencodedsemicolon`: -Defines whether requests with encoded semicolon characters in the path are allowed. (Default: ```false```) +Defines whether requests with encoded semicolon characters in the path are allowed. (Default: ```true```) `--entrypoints..http.encodedcharacters.allowencodedslash`: -Defines whether requests with encoded slash characters in the path are allowed. (Default: ```false```) +Defines whether requests with encoded slash characters in the path are allowed. (Default: ```true```) `--entrypoints..http.encodequerysemicolons`: Defines whether request query semicolons should be URLEncoded. (Default: ```false```) diff --git a/docs/content/reference/static-configuration/env-ref.md b/docs/content/reference/static-configuration/env-ref.md index 51be942b09..6947150faf 100644 --- a/docs/content/reference/static-configuration/env-ref.md +++ b/docs/content/reference/static-configuration/env-ref.md @@ -133,25 +133,25 @@ HTTP/3 configuration. (Default: ```false```) UDP port to advertise, on which HTTP/3 is available. (Default: ```0```) `TRAEFIK_ENTRYPOINTS__HTTP_ENCODEDCHARACTERS_ALLOWENCODEDBACKSLASH`: -Defines whether requests with encoded back slash characters in the path are allowed. (Default: ```false```) +Defines whether requests with encoded back slash characters in the path are allowed. (Default: ```true```) `TRAEFIK_ENTRYPOINTS__HTTP_ENCODEDCHARACTERS_ALLOWENCODEDHASH`: -Defines whether requests with encoded hash characters in the path are allowed. (Default: ```false```) +Defines whether requests with encoded hash characters in the path are allowed. (Default: ```true```) `TRAEFIK_ENTRYPOINTS__HTTP_ENCODEDCHARACTERS_ALLOWENCODEDNULLCHARACTER`: -Defines whether requests with encoded null characters in the path are allowed. (Default: ```false```) +Defines whether requests with encoded null characters in the path are allowed. (Default: ```true```) `TRAEFIK_ENTRYPOINTS__HTTP_ENCODEDCHARACTERS_ALLOWENCODEDPERCENT`: -Defines whether requests with encoded percent characters in the path are allowed. (Default: ```false```) +Defines whether requests with encoded percent characters in the path are allowed. (Default: ```true```) `TRAEFIK_ENTRYPOINTS__HTTP_ENCODEDCHARACTERS_ALLOWENCODEDQUESTIONMARK`: -Defines whether requests with encoded question mark characters in the path are allowed. (Default: ```false```) +Defines whether requests with encoded question mark characters in the path are allowed. (Default: ```true```) `TRAEFIK_ENTRYPOINTS__HTTP_ENCODEDCHARACTERS_ALLOWENCODEDSEMICOLON`: -Defines whether requests with encoded semicolon characters in the path are allowed. (Default: ```false```) +Defines whether requests with encoded semicolon characters in the path are allowed. (Default: ```true```) `TRAEFIK_ENTRYPOINTS__HTTP_ENCODEDCHARACTERS_ALLOWENCODEDSLASH`: -Defines whether requests with encoded slash characters in the path are allowed. (Default: ```false```) +Defines whether requests with encoded slash characters in the path are allowed. (Default: ```true```) `TRAEFIK_ENTRYPOINTS__HTTP_ENCODEQUERYSEMICOLONS`: Defines whether request query semicolons should be URLEncoded. (Default: ```false```) diff --git a/docs/content/routing/entrypoints.md b/docs/content/routing/entrypoints.md index 02ad3d79de..d6126df568 100644 --- a/docs/content/routing/entrypoints.md +++ b/docs/content/routing/entrypoints.md @@ -129,13 +129,13 @@ They can be defined by using a file (YAML or TOML) or CLI arguments. - "192.168.0.1" http: encodedCharacters: - allowEncodedSlash: true - allowEncodedBackSlash: true - allowEncodedNullCharacter: true - allowEncodedSemicolon: true - allowEncodedPercent: true - allowEncodedQuestionMark: true - allowEncodedHash: true + allowEncodedSlash: false + allowEncodedBackSlash: false + allowEncodedNullCharacter: false + allowEncodedSemicolon: false + allowEncodedPercent: false + allowEncodedQuestionMark: false + allowEncodedHash: false ``` ```toml tab="File (TOML)" @@ -162,13 +162,13 @@ They can be defined by using a file (YAML or TOML) or CLI arguments. insecure = true trustedIPs = ["127.0.0.1", "192.168.0.1"] [entryPoints.name.http.encodedCharacters] - allowEncodedSlash = true - allowEncodedBackSlash = true - allowEncodedNullCharacter = true - allowEncodedSemicolon = true - allowEncodedPercent = true - allowEncodedQuestionMark = true - allowEncodedHash = true + allowEncodedSlash = false + allowEncodedBackSlash = false + allowEncodedNullCharacter = false + allowEncodedSemicolon = false + allowEncodedPercent = false + allowEncodedQuestionMark = false + allowEncodedHash = false ``` ```bash tab="CLI" @@ -185,13 +185,13 @@ They can be defined by using a file (YAML or TOML) or CLI arguments. --entryPoints.name.proxyProtocol.trustedIPs=127.0.0.1,192.168.0.1 --entryPoints.name.forwardedHeaders.insecure=true --entryPoints.name.forwardedHeaders.trustedIPs=127.0.0.1,192.168.0.1 - --entryPoints.name.http.encodedCharacters.allowEncodedSlash=true - --entryPoints.name.http.encodedCharacters.allowEncodedBackSlash=true - --entryPoints.name.http.encodedCharacters.allowEncodedNullCharacter=true - --entryPoints.name.http.encodedCharacters.allowEncodedSemicolon=true - --entryPoints.name.http.encodedCharacters.allowEncodedPercent=true - --entryPoints.name.http.encodedCharacters.allowEncodedQuestionMark=true - --entryPoints.name.http.encodedCharacters.allowEncodedHash=true + --entryPoints.name.http.encodedCharacters.allowEncodedSlash=false + --entryPoints.name.http.encodedCharacters.allowEncodedBackSlash=false + --entryPoints.name.http.encodedCharacters.allowEncodedNullCharacter=false + --entryPoints.name.http.encodedCharacters.allowEncodedSemicolon=false + --entryPoints.name.http.encodedCharacters.allowEncodedPercent=false + --entryPoints.name.http.encodedCharacters.allowEncodedQuestionMark=false + --entryPoints.name.http.encodedCharacters.allowEncodedHash=false ``` ### Address @@ -1021,20 +1021,21 @@ entryPoints: ### Encoded Characters You can configure Traefik to control the handling of encoded characters in request paths for security purposes. -By default, Traefik rejects requests with path containing certain encoded characters that could be used in path traversal or other security attacks. +By default, Traefik do not reject requests with path containing certain encoded characters that could be used in path traversal or other security attacks. !!! info This check is not done against the request query parameters, but only against the request path as defined in [RFC3986 section-3](https://datatracker.ietf.org/doc/html/rfc3986#section-3). -!!! warning "Security Considerations" +!!! info "Security Considerations" - Allowing certain encoded characters may expose your application to security vulnerabilities. + When your backend is not fully compliant with [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) and notably decode encoded reserved characters in the requets path, + it is recommended to set these options to `false` to avoid split-view situation and helps prevent path traversal attacks or other malicious attempts to bypass security controls. ??? info "`encodedCharacters.allowEncodedSlash`" - _Optional, Default=false_ + _Optional, Default=true_ Controls whether requests with encoded slash characters (`%2F` or `%2f`) in the path are allowed. @@ -1045,7 +1046,7 @@ By default, Traefik rejects requests with path containing certain encoded charac address: ":80" http: encodedCharacters: - allowEncodedSlash: true + allowEncodedSlash: false ``` ```toml tab="File (TOML)" @@ -1055,18 +1056,18 @@ By default, Traefik rejects requests with path containing certain encoded charac address = ":80" [entryPoints.web.http.encodedCharacters] - allowEncodedSlash = true + allowEncodedSlash = false ``` ```bash tab="CLI" ## Static configuration --entryPoints.web.address=:80 - --entryPoints.web.http.encodedCharacters.allowEncodedSlash=true + --entryPoints.web.http.encodedCharacters.allowEncodedSlash=false ``` ??? info "`encodedCharacters.allowEncodedBackSlash`" - _Optional, Default=false_ + _Optional, Default=true_ Controls whether requests with encoded back slash characters (`%5C` or `%5c`) in the path are allowed. @@ -1077,7 +1078,7 @@ By default, Traefik rejects requests with path containing certain encoded charac address: ":80" http: encodedCharacters: - allowEncodedBackSlash: true + allowEncodedBackSlash: false ``` ```toml tab="File (TOML)" @@ -1087,18 +1088,18 @@ By default, Traefik rejects requests with path containing certain encoded charac address = ":80" [entryPoints.web.http.encodedCharacters] - allowEncodedBackSlash = true + allowEncodedBackSlash = false ``` ```bash tab="CLI" ## Static configuration --entryPoints.web.address=:80 - --entryPoints.web.http.encodedCharacters.allowEncodedBackSlash=true + --entryPoints.web.http.encodedCharacters.allowEncodedBackSlash=false ``` ??? info "`encodedCharacters.allowEncodedNullCharacter`" - _Optional, Default=false_ + _Optional, Default=true_ Controls whether requests with encoded null characters (`%00`) in the path are allowed. @@ -1109,7 +1110,7 @@ By default, Traefik rejects requests with path containing certain encoded charac address: ":80" http: encodedCharacters: - allowEncodedNullCharacter: true + allowEncodedNullCharacter: false ``` ```toml tab="File (TOML)" @@ -1119,18 +1120,18 @@ By default, Traefik rejects requests with path containing certain encoded charac address = ":80" [entryPoints.web.http.encodedCharacters] - allowEncodedNullCharacter = true + allowEncodedNullCharacter = false ``` ```bash tab="CLI" ## Static configuration --entryPoints.web.address=:80 - --entryPoints.web.http.encodedCharacters.allowEncodedNullCharacter=true + --entryPoints.web.http.encodedCharacters.allowEncodedNullCharacter=false ``` ??? info "`encodedCharacters.allowEncodedSemicolon`" - _Optional, Default=false_ + _Optional, Default=true_ Controls whether requests with encoded semicolon characters (`%3B` or `%3b`) in the path are allowed. @@ -1141,7 +1142,7 @@ By default, Traefik rejects requests with path containing certain encoded charac address: ":80" http: encodedCharacters: - allowEncodedSemicolon: true + allowEncodedSemicolon: false ``` ```toml tab="File (TOML)" @@ -1151,18 +1152,18 @@ By default, Traefik rejects requests with path containing certain encoded charac address = ":80" [entryPoints.web.http.encodedCharacters] - allowEncodedSemicolon = true + allowEncodedSemicolon = false ``` ```bash tab="CLI" ## Static configuration --entryPoints.web.address=:80 - --entryPoints.web.http.encodedCharacters.allowEncodedSemicolon=true + --entryPoints.web.http.encodedCharacters.allowEncodedSemicolon=false ``` ??? info "`encodedCharacters.allowEncodedPercent`" - _Optional, Default=false_ + _Optional, Default=true_ Controls whether requests with encoded percent characters (`%25`) in the path are allowed. @@ -1173,7 +1174,7 @@ By default, Traefik rejects requests with path containing certain encoded charac address: ":80" http: encodedCharacters: - allowEncodedPercent: true + allowEncodedPercent: false ``` ```toml tab="File (TOML)" @@ -1183,18 +1184,18 @@ By default, Traefik rejects requests with path containing certain encoded charac address = ":80" [entryPoints.web.http.encodedCharacters] - allowEncodedPercent = true + allowEncodedPercent = false ``` ```bash tab="CLI" ## Static configuration --entryPoints.web.address=:80 - --entryPoints.web.http.encodedCharacters.allowEncodedPercent=true + --entryPoints.web.http.encodedCharacters.allowEncodedPercent=false ``` ??? info "`encodedCharacters.allowEncodedQuestionMark`" - _Optional, Default=false_ + _Optional, Default=true_ Controls whether requests with encoded question mark characters (`%3F` or `%3f`) in the path are allowed. @@ -1205,7 +1206,7 @@ By default, Traefik rejects requests with path containing certain encoded charac address: ":80" http: encodedCharacters: - allowEncodedQuestionMark: true + allowEncodedQuestionMark: false ``` ```toml tab="File (TOML)" @@ -1215,18 +1216,18 @@ By default, Traefik rejects requests with path containing certain encoded charac address = ":80" [entryPoints.web.http.encodedCharacters] - allowEncodedQuestionMark = true + allowEncodedQuestionMark = false ``` ```bash tab="CLI" ## Static configuration --entryPoints.web.address=:80 - --entryPoints.web.http.encodedCharacters.allowEncodedQuestionMark=true + --entryPoints.web.http.encodedCharacters.allowEncodedQuestionMark=false ``` ??? info "`encodedCharacters.allowEncodedHash`" - _Optional, Default=false_ + _Optional, Default=true_ Controls whether requests with encoded hash characters (`%23`) in the path are allowed. @@ -1237,7 +1238,7 @@ By default, Traefik rejects requests with path containing certain encoded charac address: ":80" http: encodedCharacters: - allowEncodedHash: true + allowEncodedHash: false ``` ```toml tab="File (TOML)" @@ -1247,13 +1248,13 @@ By default, Traefik rejects requests with path containing certain encoded charac address = ":80" [entryPoints.web.http.encodedCharacters] - allowEncodedHash = true + allowEncodedHash = false ``` ```bash tab="CLI" ## Static configuration --entryPoints.web.address=:80 - --entryPoints.web.http.encodedCharacters.allowEncodedHash=true + --entryPoints.web.http.encodedCharacters.allowEncodedHash=false ``` ### SanitizePath diff --git a/docs/content/security/request-path.md b/docs/content/security/request-path.md index 4643913560..fe88c31420 100644 --- a/docs/content/security/request-path.md +++ b/docs/content/security/request-path.md @@ -20,7 +20,7 @@ When Traefik receives an HTTP request, it processes the request path through sev Traefik inspects the path for potentially dangerous encoded characters and rejects requests containing them unless explicitly allowed. -Here is the list of the encoded characters that are rejected by default: +Here is the list of the encoded characters that are allowed by default: | Encoded Character | Character | |-------------------|-------------------------| @@ -87,7 +87,12 @@ Configure it in the [EntryPoints](../routing/entrypoints.md#encoded-characters) This filtering occurs before path sanitization and catches attack attempts that use encoding to bypass other security controls. -All encoded character filtering is enabled by default (`false` means encoded characters are rejected), providing maximum security: +All encoded character filtering is disabled by default (`true` means encoded characters are allowed). + +!!! info "Security Considerations" + + When your backend is not fully compliant with [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) and notably decode encoded reserved characters in the requets path, + it is recommended to set these options to `false` to avoid split-view situation and helps prevent path traversal attacks or other malicious attempts to bypass security controls. ```yaml tab="File (YAML)" entryPoints: @@ -95,13 +100,13 @@ entryPoints: address: ":443" http: encodedCharacters: - allowEncodedSlash: false # %2F - Default: false (RECOMMENDED) - allowEncodedBackSlash: false # %5C - Default: false (RECOMMENDED) - allowEncodedNullCharacter: false # %00 - Default: false (RECOMMENDED) - allowEncodedSemicolon: false # %3B - Default: false (RECOMMENDED) - allowEncodedPercent: false # %25 - Default: false (RECOMMENDED) - allowEncodedQuestionMark: false # %3F - Default: false (RECOMMENDED) - allowEncodedHash: false # %23 - Default: false (RECOMMENDED) + allowEncodedSlash: false # %2F - Default: true + allowEncodedBackSlash: false # %5C - Default: true + allowEncodedNullCharacter: false # %00 - Default: true + allowEncodedSemicolon: false # %3B - Default: true + allowEncodedPercent: false # %25 - Default: true + allowEncodedQuestionMark: false # %3F - Default: true + allowEncodedHash: false # %23 - Default: true ``` ```toml tab="File (TOML)" diff --git a/integration/fixtures/simple_encoded_chars.toml b/integration/fixtures/simple_encoded_chars.toml index 56f645ca34..669c60b9b9 100644 --- a/integration/fixtures/simple_encoded_chars.toml +++ b/integration/fixtures/simple_encoded_chars.toml @@ -8,12 +8,18 @@ [entryPoints] [entryPoints.strict] address = ":8000" - # Default: no encoded characters allowed + [entryPoints.strict.http.encodedCharacters] + allowEncodedSlash = false [entryPoints.permissive] address = ":8001" + # No config, default values should apply + + [entryPoints.permissive2] + address = ":8002" + # No config for allowEncodedSlash, default value is effectively true [entryPoints.permissive.http.encodedCharacters] - allowEncodedSlash = true + allowEncodedBackSlash = false [api] insecure = true diff --git a/integration/fixtures/websocket/config.toml b/integration/fixtures/websocket/config.toml index c4a25c48b7..83a499ce75 100644 --- a/integration/fixtures/websocket/config.toml +++ b/integration/fixtures/websocket/config.toml @@ -8,8 +8,6 @@ [entryPoints] [entryPoints.web] address = ":8000" - [entryPoints.web.http.encodedCharacters] - allowEncodedSlash = true [api] insecure = true diff --git a/integration/simple_test.go b/integration/simple_test.go index 2b85b8e2c6..c2f1392c42 100644 --- a/integration/simple_test.go +++ b/integration/simple_test.go @@ -1520,6 +1520,12 @@ func (s *SimpleSuite) TestEncodedCharactersDifferentEntryPoints() { target: "127.0.0.1:8001", // permissive entry point expected: http.StatusOK, }, + { + desc: "Encoded slash should be ALLOWED on permissive2 entry point", + request: "GET /path%2Fwith%2Fslash HTTP/1.1\r\nHost: test.localhost\r\n\r\n", + target: "127.0.0.1:8002", // permissive2 entry point + expected: http.StatusOK, + }, { desc: "Regular path should work on strict entry point", request: "GET /regular/path HTTP/1.1\r\nHost: test.localhost\r\n\r\n", @@ -1532,6 +1538,12 @@ func (s *SimpleSuite) TestEncodedCharactersDifferentEntryPoints() { target: "127.0.0.1:8001", expected: http.StatusOK, }, + { + desc: "Regular path should work on permissive2 entry point", + request: "GET /regular/path HTTP/1.1\r\nHost: test.localhost\r\n\r\n", + target: "127.0.0.1:8002", + expected: http.StatusOK, + }, } for _, test := range testCases { diff --git a/pkg/config/dynamic/http_config.go b/pkg/config/dynamic/http_config.go index 3bd9c43643..d397d23069 100644 --- a/pkg/config/dynamic/http_config.go +++ b/pkg/config/dynamic/http_config.go @@ -43,14 +43,14 @@ type Service struct { // Router holds the router configuration. type Router struct { - EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty" export:"true"` - Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"` - Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"` - Rule string `json:"rule,omitempty" toml:"rule,omitempty" yaml:"rule,omitempty"` - Priority int `json:"priority,omitempty" toml:"priority,omitempty,omitzero" yaml:"priority,omitempty" export:"true"` - TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"` - DefaultRule bool `json:"-" toml:"-" yaml:"-" label:"-" file:"-"` - DeniedEncodedPathCharacters RouterDeniedEncodedPathCharacters `json:"-" toml:"-" yaml:"-" label:"-" file:"-"` + EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty" export:"true"` + Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"` + Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"` + Rule string `json:"rule,omitempty" toml:"rule,omitempty" yaml:"rule,omitempty"` + Priority int `json:"priority,omitempty" toml:"priority,omitempty,omitzero" yaml:"priority,omitempty" export:"true"` + TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"` + DefaultRule bool `json:"-" toml:"-" yaml:"-" label:"-" file:"-"` + DeniedEncodedPathCharacters *RouterDeniedEncodedPathCharacters `json:"-" toml:"-" yaml:"-" label:"-" file:"-" kv:"-"` } // +k8s:deepcopy-gen=true diff --git a/pkg/config/dynamic/zz_generated.deepcopy.go b/pkg/config/dynamic/zz_generated.deepcopy.go index 068300ab8c..b8f68c946a 100644 --- a/pkg/config/dynamic/zz_generated.deepcopy.go +++ b/pkg/config/dynamic/zz_generated.deepcopy.go @@ -1035,7 +1035,11 @@ func (in *Router) DeepCopyInto(out *Router) { *out = new(RouterTLSConfig) (*in).DeepCopyInto(*out) } - out.DeniedEncodedPathCharacters = in.DeniedEncodedPathCharacters + if in.DeniedEncodedPathCharacters != nil { + in, out := &in.DeniedEncodedPathCharacters, &out.DeniedEncodedPathCharacters + *out = new(RouterDeniedEncodedPathCharacters) + **out = **in + } return } diff --git a/pkg/config/static/entrypoints.go b/pkg/config/static/entrypoints.go index 29f37fa138..ad98636430 100644 --- a/pkg/config/static/entrypoints.go +++ b/pkg/config/static/entrypoints.go @@ -84,6 +84,16 @@ type EncodedCharacters struct { AllowEncodedHash bool `description:"Defines whether requests with encoded hash characters in the path are allowed." json:"allowEncodedHash,omitempty" toml:"allowEncodedHash,omitempty" yaml:"allowEncodedHash,omitempty" export:"true"` } +func (ec *EncodedCharacters) SetDefaults() { + ec.AllowEncodedSlash = true + ec.AllowEncodedBackSlash = true + ec.AllowEncodedNullCharacter = true + ec.AllowEncodedSemicolon = true + ec.AllowEncodedPercent = true + ec.AllowEncodedQuestionMark = true + ec.AllowEncodedHash = true +} + // HTTP2Config is the HTTP2 configuration of an entry point. type HTTP2Config struct { MaxConcurrentStreams int32 `description:"Specifies the number of concurrent streams per connection that each client is allowed to initiate." json:"maxConcurrentStreams,omitempty" toml:"maxConcurrentStreams,omitempty" yaml:"maxConcurrentStreams,omitempty" export:"true"` diff --git a/pkg/server/aggregator.go b/pkg/server/aggregator.go index 697fe3cf83..28d07dda9a 100644 --- a/pkg/server/aggregator.go +++ b/pkg/server/aggregator.go @@ -167,7 +167,7 @@ func applyModel(cfg dynamic.Configuration) dynamic.Configuration { if m.DeniedEncodedPathCharacters != nil { // As the denied encoded path characters option is not configurable at the router level, // we can simply copy the whole structure to override the router's default config. - cp.DeniedEncodedPathCharacters = *m.DeniedEncodedPathCharacters + cp.DeniedEncodedPathCharacters = m.DeniedEncodedPathCharacters } rtName := name diff --git a/pkg/server/router/deny.go b/pkg/server/router/deny.go index 9c64af1195..423fdb6961 100644 --- a/pkg/server/router/deny.go +++ b/pkg/server/router/deny.go @@ -2,29 +2,10 @@ package router import ( "net/http" - "strings" "github.com/traefik/traefik/v2/pkg/log" ) -// denyFragment rejects the request if the URL path contains a fragment (hash character). -// When go receives an HTTP request, it assumes the absence of fragment URL. -// However, it is still possible to send a fragment in the request. -// In this case, Traefik will encode the '#' character, altering the request's intended meaning. -// To avoid this behavior, the following function rejects requests that include a fragment in the URL. -func denyFragment(h http.Handler) http.Handler { - return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - if strings.Contains(req.URL.RawPath, "#") { - log.WithoutContext().Debugf("Rejecting request because it contains a fragment in the URL path: %s", req.URL.RawPath) - rw.WriteHeader(http.StatusBadRequest) - - return - } - - h.ServeHTTP(rw, req) - }) -} - // denyEncodedPathCharacters reject the request if the escaped path contains encoded characters in the given list. func denyEncodedPathCharacters(encodedCharacters map[string]struct{}, h http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { diff --git a/pkg/server/router/deny_test.go b/pkg/server/router/deny_test.go index 19ece60138..de17fe5fc3 100644 --- a/pkg/server/router/deny_test.go +++ b/pkg/server/router/deny_test.go @@ -8,42 +8,6 @@ import ( "github.com/stretchr/testify/assert" ) -func Test_denyFragment(t *testing.T) { - tests := []struct { - name string - url string - wantStatus int - }{ - { - name: "Rejects fragment character", - url: "http://example.com/#", - wantStatus: http.StatusBadRequest, - }, - { - name: "Allows without fragment", - url: "http://example.com/", - wantStatus: http.StatusOK, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - t.Parallel() - - handler := denyFragment(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - })) - - req := httptest.NewRequest(http.MethodGet, test.url, nil) - res := httptest.NewRecorder() - - handler.ServeHTTP(res, req) - - assert.Equal(t, test.wantStatus, res.Code) - }) - } -} - func Test_denyEncodedPathCharacters(t *testing.T) { tests := []struct { name string diff --git a/pkg/server/router/router.go b/pkg/server/router/router.go index 2d46f7388a..f01210bfa6 100644 --- a/pkg/server/router/router.go +++ b/pkg/server/router/router.go @@ -223,14 +223,11 @@ func (m *Manager) buildHTTPHandler(ctx context.Context, router *runtime.RouterIn chain = chain.Append(denyrouterrecursion.WrapHandler(routerName)) } - // Here we are adding deny handlers for encoded path characters and fragment. - // Deny handler are only added for root routers, child routers are protected by their parent router deny handlers. - chain = chain.Append(func(next http.Handler) (http.Handler, error) { - return denyFragment(next), nil - }) - chain = chain.Append(func(next http.Handler) (http.Handler, error) { - return denyEncodedPathCharacters(router.DeniedEncodedPathCharacters.Map(), next), nil - }) + if router.DeniedEncodedPathCharacters != nil { + chain = chain.Append(func(next http.Handler) (http.Handler, error) { + return denyEncodedPathCharacters(router.DeniedEncodedPathCharacters.Map(), next), nil + }) + } return chain.Extend(*mHandler).Append(tHandler).Then(sHandler) } diff --git a/pkg/server/router/router_test.go b/pkg/server/router/router_test.go index 1c669cf09a..add135bc59 100644 --- a/pkg/server/router/router_test.go +++ b/pkg/server/router/router_test.go @@ -910,13 +910,16 @@ func TestManager_BuildHandlers_Deny(t *testing.T) { expectedStatusCode int }{ { - desc: "unallowed request with encoded slash", + desc: "disallow request with encoded slash", requestPath: "/foo%2F", routers: map[string]*dynamic.Router{ "parent": { EntryPoints: []string{"web"}, Rule: "PathPrefix(`/`)", Service: "service", + DeniedEncodedPathCharacters: &dynamic.RouterDeniedEncodedPathCharacters{ + AllowEncodedSlash: false, + }, }, }, services: map[string]*dynamic.Service{ @@ -936,9 +939,6 @@ func TestManager_BuildHandlers_Deny(t *testing.T) { EntryPoints: []string{"web"}, Rule: "PathPrefix(`/`)", Service: "service", - DeniedEncodedPathCharacters: dynamic.RouterDeniedEncodedPathCharacters{ - AllowEncodedSlash: true, - }, }, }, services: map[string]*dynamic.Service{ @@ -950,25 +950,6 @@ func TestManager_BuildHandlers_Deny(t *testing.T) { }, expectedStatusCode: http.StatusBadGateway, }, - { - desc: "unallowed request with fragment", - requestPath: "/foo#", - routers: map[string]*dynamic.Router{ - "parent": { - EntryPoints: []string{"web"}, - Rule: "PathPrefix(`/`)", - Service: "service", - }, - }, - services: map[string]*dynamic.Service{ - "service": { - LoadBalancer: &dynamic.ServersLoadBalancer{ - Servers: []dynamic.Server{{URL: "http://localhost:8080"}}, - }, - }, - }, - expectedStatusCode: http.StatusBadRequest, - }, } for _, test := range testCases { diff --git a/pkg/server/server_entrypoint_tcp.go b/pkg/server/server_entrypoint_tcp.go index 51b946c09c..47d5c941c7 100644 --- a/pkg/server/server_entrypoint_tcp.go +++ b/pkg/server/server_entrypoint_tcp.go @@ -606,6 +606,8 @@ func createHTTPServer(ctx context.Context, ln net.Listener, configuration *stati handler = normalizePath(handler) + handler = denyFragment(handler) + serverHTTP := &http.Server{ Protocols: &protocols, Handler: handler, @@ -685,6 +687,24 @@ func (t *trackedConnection) Close() error { return t.WriteCloser.Close() } +// denyFragment rejects the request if the URL path contains a fragment (hash character). +// When go receives an HTTP request, it assumes the absence of fragment URL. +// However, it is still possible to send a fragment in the request. +// In this case, Traefik will encode the '#' character, altering the request's intended meaning. +// To avoid this behavior, the following function rejects requests that include a fragment in the URL. +func denyFragment(h http.Handler) http.Handler { + return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + if strings.Contains(req.URL.RawPath, "#") { + log.WithoutContext().Debugf("Rejecting request because it contains a fragment in the URL path: %s", req.URL.RawPath) + rw.WriteHeader(http.StatusBadRequest) + + return + } + + h.ServeHTTP(rw, req) + }) +} + // This function is inspired by http.AllowQuerySemicolons. func encodeQuerySemicolons(h http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { diff --git a/pkg/server/server_entrypoint_tcp_test.go b/pkg/server/server_entrypoint_tcp_test.go index 3a56856b39..dbcde6b006 100644 --- a/pkg/server/server_entrypoint_tcp_test.go +++ b/pkg/server/server_entrypoint_tcp_test.go @@ -388,6 +388,42 @@ func TestKeepAliveH2c(t *testing.T) { require.Contains(t, err.Error(), "use of closed network connection") } +func Test_denyFragment(t *testing.T) { + tests := []struct { + name string + url string + wantStatus int + }{ + { + name: "Rejects fragment character", + url: "http://example.com/#", + wantStatus: http.StatusBadRequest, + }, + { + name: "Allows without fragment", + url: "http://example.com/", + wantStatus: http.StatusOK, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + handler := denyFragment(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + + req := httptest.NewRequest(http.MethodGet, test.url, nil) + res := httptest.NewRecorder() + + handler.ServeHTTP(res, req) + + assert.Equal(t, test.wantStatus, res.Code) + }) + } +} + func TestSanitizePath(t *testing.T) { tests := []struct { path string From 9e5d4ba5a1cdcf3465630cef858945f90f6b4279 Mon Sep 17 00:00:00 2001 From: Kevin Pollet Date: Wed, 14 Jan 2026 10:28:04 +0100 Subject: [PATCH 4/4] Prepare release v2.11.35 --- CHANGELOG.md | 7 +++++++ script/gcg/traefik-bugfix.toml | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9930ef14d6..3e1736b318 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [v2.11.35](https://github.com/traefik/traefik/tree/v2.11.35) (2026-01-14) +[All Commits](https://github.com/traefik/traefik/compare/v2.11.34...v2.11.35) + +**Bug fixes:** +- **[acme]** Add timeout to ACME-TLS/1 challenge handshake ([#12516](https://github.com/traefik/traefik/pull/12516) by [LBF38](https://github.com/LBF38)) +- **[server]** Make encoded character options opt-in ([#12540](https://github.com/traefik/traefik/pull/12540) by [gndz07](https://github.com/gndz07)) + ## [v2.11.34](https://github.com/traefik/traefik/tree/v2.11.34) (2025-12-23) [All Commits](https://github.com/traefik/traefik/compare/v2.11.33...v2.11.34) diff --git a/script/gcg/traefik-bugfix.toml b/script/gcg/traefik-bugfix.toml index cdb8a357fa..640bbc3ea7 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 v2.11.34 +# example new bugfix v2.11.35 CurrentRef = "v2.11" -PreviousRef = "v2.11.33" +PreviousRef = "v2.11.34" BaseBranch = "v2.11" -FutureCurrentRefName = "v2.11.34" +FutureCurrentRefName = "v2.11.35" ThresholdPreviousRef = 10000 ThresholdCurrentRef = 10000