TLS certificate validation: SAN/peer certificate verification improvements (MITM risk reduction)
Description
The commit adds support for PeerCertSANs and deprecates PeerCertURI to tighten TLS peer certificate verification for backend connections. Previously, backend TLS policy could rely on legacy or insufficient validation (e.g., using PeerCertURI and/or CN) without explicit SAN verification, creating a potential TLS/MITM bypass where a certificate could appear valid despite SANs not being properly validated. The fix introduces explicit SAN-based matching (PeerCertSANs) and deprecates the older PeerCertURI path, updating defaults/docs to ensure SANs are explicitly verified during TLS handshakes.
Commit Details
Author: Ali Amer
Date: 2026-06-24 14:48 UTC
Message:
Support TLS and Backend TLS Policy SAN validation
Triage Assessment
Vulnerability Type: TLS/SSL certificate validation (SAN validation)
Confidence: HIGH
Reasoning:
Adds support for PeerCertSANs and SAN validation in TLS configurations, deprecates insecure/legacy PeerCertURI usage, and updates defaults/docs. This tightens peer certificate verification and mitigates potential MITM/X509 validation bypass by ensuring SANs are explicitly verified during TLS handshakes.
Verification Assessment
Vulnerability Type: TLS certificate validation: SAN/peer certificate verification improvements (MITM risk reduction)
Confidence: HIGH
Affected Versions: Versions prior to 3.7.0-ea.3 (3.7.x before this patch)
Code Diff
diff --git a/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml b/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
index 9819b8aad2..0532786e8d 100644
--- a/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
+++ b/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
@@ -2493,9 +2493,25 @@ spec:
description: MinVersion defines the minimum TLS version to use when
contacting backend servers.
type: string
+ peerCertSANs:
+ description: PeerCertSANs defines the peer cert Subject Alternative
+ Names used to match against SAN during the peer certificate verification.
+ items:
+ description: SAN represents a Subject Alternative Name.
+ properties:
+ type:
+ description: SANType is the type of the Subject Alternative
+ Name.
+ type: string
+ value:
+ type: string
+ type: object
+ type: array
peerCertURI:
- description: PeerCertURI defines the peer cert URI used to match against
- SAN URI during the peer certificate verification.
+ description: |-
+ PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
+
+ Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
type: string
rootCAs:
description: RootCAs defines a list of CA certificate Secrets or ConfigMaps
@@ -2647,10 +2663,26 @@ spec:
insecureSkipVerify:
description: InsecureSkipVerify disables TLS certificate verification.
type: boolean
+ peerCertSANs:
+ description: PeerCertSANs defines the peer cert Subject Alternative
+ Names used to match against SAN during the peer certificate
+ verification.
+ items:
+ description: SAN represents a Subject Alternative Name.
+ properties:
+ type:
+ description: SANType is the type of the Subject Alternative
+ Name.
+ type: string
+ value:
+ type: string
+ type: object
+ type: array
peerCertURI:
description: |-
- MaxIdleConnsPerHost controls the maximum idle (keep-alive) to keep per-host.
PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
+
+ Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
type: string
rootCAs:
description: RootCAs defines a list of CA certificate Secrets
diff --git a/docs/content/reference/dynamic-configuration/traefik.io_serverstransports.yaml b/docs/content/reference/dynamic-configuration/traefik.io_serverstransports.yaml
index 27808e27a9..c62ff5fbaf 100644
--- a/docs/content/reference/dynamic-configuration/traefik.io_serverstransports.yaml
+++ b/docs/content/reference/dynamic-configuration/traefik.io_serverstransports.yaml
@@ -123,9 +123,25 @@ spec:
description: MinVersion defines the minimum TLS version to use when
contacting backend servers.
type: string
+ peerCertSANs:
+ description: PeerCertSANs defines the peer cert Subject Alternative
+ Names used to match against SAN during the peer certificate verification.
+ items:
+ description: SAN represents a Subject Alternative Name.
+ properties:
+ type:
+ description: SANType is the type of the Subject Alternative
+ Name.
+ type: string
+ value:
+ type: string
+ type: object
+ type: array
peerCertURI:
- description: PeerCertURI defines the peer cert URI used to match against
- SAN URI during the peer certificate verification.
+ description: |-
+ PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
+
+ Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
type: string
rootCAs:
description: RootCAs defines a list of CA certificate Secrets or ConfigMaps
diff --git a/docs/content/reference/dynamic-configuration/traefik.io_serverstransporttcps.yaml b/docs/content/reference/dynamic-configuration/traefik.io_serverstransporttcps.yaml
index 1f57374ede..f0ceab2e7a 100644
--- a/docs/content/reference/dynamic-configuration/traefik.io_serverstransporttcps.yaml
+++ b/docs/content/reference/dynamic-configuration/traefik.io_serverstransporttcps.yaml
@@ -93,10 +93,26 @@ spec:
insecureSkipVerify:
description: InsecureSkipVerify disables TLS certificate verification.
type: boolean
+ peerCertSANs:
+ description: PeerCertSANs defines the peer cert Subject Alternative
+ Names used to match against SAN during the peer certificate
+ verification.
+ items:
+ description: SAN represents a Subject Alternative Name.
+ properties:
+ type:
+ description: SANType is the type of the Subject Alternative
+ Name.
+ type: string
+ value:
+ type: string
+ type: object
+ type: array
peerCertURI:
description: |-
- MaxIdleConnsPerHost controls the maximum idle (keep-alive) to keep per-host.
PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
+
+ Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
type: string
rootCAs:
description: RootCAs defines a list of CA certificate Secrets
diff --git a/integration/fixtures/k8s/01-traefik-crd.yml b/integration/fixtures/k8s/01-traefik-crd.yml
index b5f614949a..c86fbea5ca 100644
--- a/integration/fixtures/k8s/01-traefik-crd.yml
+++ b/integration/fixtures/k8s/01-traefik-crd.yml
@@ -2494,9 +2494,25 @@ spec:
description: MinVersion defines the minimum TLS version to use when
contacting backend servers.
type: string
+ peerCertSANs:
+ description: PeerCertSANs defines the peer cert Subject Alternative
+ Names used to match against SAN during the peer certificate verification.
+ items:
+ description: SAN represents a Subject Alternative Name.
+ properties:
+ type:
+ description: SANType is the type of the Subject Alternative
+ Name.
+ type: string
+ value:
+ type: string
+ type: object
+ type: array
peerCertURI:
- description: PeerCertURI defines the peer cert URI used to match against
- SAN URI during the peer certificate verification.
+ description: |-
+ PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
+
+ Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
type: string
rootCAs:
description: RootCAs defines a list of CA certificate Secrets or ConfigMaps
@@ -2648,10 +2664,26 @@ spec:
insecureSkipVerify:
description: InsecureSkipVerify disables TLS certificate verification.
type: boolean
+ peerCertSANs:
+ description: PeerCertSANs defines the peer cert Subject Alternative
+ Names used to match against SAN during the peer certificate
+ verification.
+ items:
+ description: SAN represents a Subject Alternative Name.
+ properties:
+ type:
+ description: SANType is the type of the Subject Alternative
+ Name.
+ type: string
+ value:
+ type: string
+ type: object
+ type: array
peerCertURI:
description: |-
- MaxIdleConnsPerHost controls the maximum idle (keep-alive) to keep per-host.
PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
+
+ Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
type: string
rootCAs:
description: RootCAs defines a list of CA certificate Secrets
diff --git a/integration/gateway-api-conformance-reports/v1.5.1/experimental-v3.7-default-report.yaml b/integration/gateway-api-conformance-reports/v1.5.1/experimental-v3.7-default-report.yaml
index 8b963c2e14..e3b5e22971 100644
--- a/integration/gateway-api-conformance-reports/v1.5.1/experimental-v3.7-default-report.yaml
+++ b/integration/gateway-api-conformance-reports/v1.5.1/experimental-v3.7-default-report.yaml
@@ -30,10 +30,11 @@ profiles:
result: success
statistics:
Failed: 0
- Passed: 20
+ Passed: 21
Skipped: 0
supportedFeatures:
- BackendTLSPolicy
+ - BackendTLSPolicySANValidation
- GatewayPort8080
- HTTPRouteBackendProtocolH2C
- HTTPRouteBackendProtocolWebSocket
@@ -48,7 +49,6 @@ profiles:
- HTTPRouteResponseHeaderModification
- HTTPRouteSchemeRedirect
unsupportedFeatures:
- - BackendTLSPolicySANValidation
- GatewayAddressEmpty
- GatewayBackendClientCertificate
- GatewayFrontendClientCertificateValidation
diff --git a/pkg/config/dynamic/http_config.go b/pkg/config/dynamic/http_config.go
index 17682ef269..39d271a6e1 100644
--- a/pkg/config/dynamic/http_config.go
+++ b/pkg/config/dynamic/http_config.go
@@ -537,8 +537,10 @@ type ServersTransport struct {
MaxIdleConnsPerHost int `description:"If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used. If negative, disables connection reuse." json:"maxIdleConnsPerHost,omitempty" toml:"maxIdleConnsPerHost,omitempty" yaml:"maxIdleConnsPerHost,omitempty" export:"true"`
ForwardingTimeouts *ForwardingTimeouts `description:"Defines the timeouts for requests forwarded to the backend servers." json:"forwardingTimeouts,omitempty" toml:"forwardingTimeouts,omitempty" yaml:"forwardingTimeouts,omitempty" export:"true"`
DisableHTTP2 bool `description:"Disables HTTP/2 for connections with backend servers." json:"disableHTTP2,omitempty" toml:"disableHTTP2,omitempty" yaml:"disableHTTP2,omitempty" export:"true"`
- PeerCertURI string `description:"Defines the URI used to match against SAN URI during the peer certificate verification." json:"peerCertURI,omitempty" toml:"peerCertURI,omitempty" yaml:"peerCertURI,omitempty" export:"true"`
- Spiffe *Spiffe `description:"Defines the SPIFFE configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
+ // Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
+ PeerCertURI string `description:"Defines the URI used to match against SAN URI during the peer certificate verification." json:"peerCertURI,omitempty" toml:"peerCertURI,omitempty" yaml:"peerCertURI,omitempty"`
+ PeerCertSANs []traefiktls.SAN `description:"Defines the SANs (Subject Alternative Names) used to match against SANs during the peer certificate verification." json:"peerCertSANs,omitempty" toml:"peerCertSANs,omitempty" yaml:"peerCertSANs,omitempty"`
+ Spiffe *Spiffe `description:"Defines the SPIFFE configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
}
// +k8s:deepcopy-gen=true
diff --git a/pkg/config/dynamic/tcp_config.go b/pkg/config/dynamic/tcp_config.go
index ce7bfb885b..b28cce2f4e 100644
--- a/pkg/config/dynamic/tcp_config.go
+++ b/pkg/config/dynamic/tcp_config.go
@@ -207,8 +207,10 @@ type TLSClientConfig struct {
InsecureSkipVerify bool `description:"Disables SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
RootCAs []types.FileOrContent `description:"Defines a list of CA certificates used to validate server certificates." json:"rootCAs,omitempty" toml:"rootCAs,omitempty" yaml:"rootCAs,omitempty"`
Certificates traefiktls.Certificates `description:"Defines a list of client certificates for mTLS." json:"certificates,omitempty" toml:"certificates,omitempty" yaml:"certificates,omitempty" export:"true"`
- PeerCertURI string `description:"Defines the URI used to match against SAN URI during the peer certificate verification." json:"peerCertURI,omitempty" toml:"peerCertURI,omitempty" yaml:"peerCertURI,omitempty" export:"true"`
- Spiffe *Spiffe `description:"Defines the SPIFFE TLS configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
+ // Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
+ PeerCertURI string `description:"Defines the URI used to match against SAN URI during the peer cert
... [truncated]