Repository: envoyproxy/gateway

Issue:
Bug in logic detecting overlapping cert SANs
*Description*:

1. This issue is not a duplicate of #6321.
2. The cause of this issue is mistakenly treating all absolute domain names as wildcard domain names for comparison.
3. Use 'strings.HasSuffix' for comparison is reckless, because [the wildcard applies only to one level of the domain name](https://en.wikipedia.org/wiki/Public_key_certificate#Further_examples).

*Repro steps*:

1. Add a listener for `foo.example.com` and `pdf.foo.example.com`.
※ Use `*.example.com` and `pdf.foo.example.com` should also trigger the issue.
3. Use cert-manager to issue certs for them (note that a wildcard certificate should not be used)
4. Look in the logs to see a warning about overlapping SANs

Sample Gateway Listeners
```yaml
listeners:
  - name: foo
    hostname: foo.example.com
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
        - name: foo-tls
  - name: foo-pdf
    hostname: pdf.foo.example.com
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
        - name: foo-pdf-tls
```

*Environment*:
Envoy Gateway v1.5.3

*Logs*:
```
Message:  The certificate SAN pdf.foo.example.com overlaps with the certificate SAN foo.example.com in listener foo. ALPN will default to HTTP/1.1 to prevent HTTP/2 connection coalescing, unless explicitly configured via ClientTrafficPolicy
Reason: OverlappingCertificates
Type: OverlappingTLSConfig
```


Hints from issue comments:
@jing8956: The original submitter is @zhaohuabing

Regarding the code to fix this issue, I can only provide C# code as a reference.
```csharp
[TestClass]
public sealed class Test
{
    public bool isOverlappingHostname(string? name1, string? name2)
    {
        if (name1 == null || name2 == null) return true;
        if (string.Equals(name1, name2)) return true;

        if (isSubdomain(name1, name2)) return true;
        if (isSubdomain(name2, name1)) return true;

        return false;
    }

    public bool isSubdomain(string pattern, string name)
    {
        // eg: pattern = "*.example.com", name = "foo.example.com"
        if (pattern.Length == 0) return false;
        if (pattern[0] != '*') return false;

        var suffix = pattern.Substring(startIndex: 1); // suffix = ".example.com"
        if (!name.EndsWith(suffix)) return false;

        var labelLength = name.Length - suffix.Length;
        var label = name.Substring(startIndex: 0, length: labelLength); // label = "foo"
        if (label.Contains('.')) return false; // The wildcard applies only to one level of the domain name.

        return true;
    }

    [TestMethod]
    [DataRow("example.com", "example.com", true, DisplayName = "exact match")]
    [DataRow("*.example.com", "*.example.com", true, DisplayName = "two wildcards with same suffix")]
    [DataRow("*.example.com", "*.test.example.com", false, DisplayName = "two wildcards matches subdomain")] // Edited. The wildcard applies only to one level of the domain name.
    [DataRow(null, "www.example.com", true, DisplayName = "nil hostname matches all")]
    [DataRow(null, "*.example.com", true, DisplayName = "nil hostname matches subdomain")]
    [DataRow(null, null, true, DisplayName = "two nil hostnames")]
    [DataRow("*.example.com", "test.example.com", true, DisplayName = "wildcard matches exact")]
    [DataRow("*.example.com", "sub.test.example.com", false, DisplayName = "wildcard matches subdomain")] // Edited. The wildcard applies only to one level of the domain name.
    [DataRow("*.example.com", "example.com", false, DisplayName = "wildcard matches empty subdomain")] // Edited. The wildcard applies only to one level of the domain name.

    [DataRow("example.com", "test.com", false, DisplayName = "different domains")]
    [DataRow("*.example.com", "test.com", false, DisplayName = "wildcard doesn't match different domain")]
    [DataRow("*.example.com", "*.test.com", false, DisplayName = "different wildcard domains")]
    [DataRow("api.foo.dev", "testing-api.foo.dev", false, DisplayName = "different sub domains of same domain")]
    public void TestMethod(string? name1, string? name2, bool expected)
    {
        var actual = isOverlappingHostname(name1, name2);
        Assert.AreEqual(expected, actual);
    }
}
```
I haven't studied the Go language, so unable to submit code.@rudrakhp: @jing8956 should this be treated as overlap according to your suggestion? Because currently we do. https://github.com/envoyproxy/gateway/blob/a4aa88dc5c8608a2c68818ed7d5855f22fd1dd90/internal/gatewayapi/listener_test.go#L122-L127@jing8956: @rudrakhp This test is incorrect.
`*.example.com` certificate is not valid for `*.test.example.com`, no overlap between them.
`*.example.com` is valid for `test.example.com` , `foo-test.example.com` , and so on.@rudrakhp: @jing8956 I think you might be right, found this in [Istio](https://github.com/istio/istio/blob/6325983cda59b8423a80e5e3827115945ba94285/pkg/config/host/name.go#L37).

Solution patch:
diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go
index 5938ae594..122562934 100644
--- a/internal/gatewayapi/listener.go
+++ b/internal/gatewayapi/listener.go
@@ -246,7 +246,7 @@ func checkOverlappingHostnames(httpsListeners []*ListenerContext) {
 			if httpsListeners[i].Port != httpsListeners[j].Port {
 				continue
 			}
-			if isOverlappingHostname(httpsListeners[i].Hostname, httpsListeners[j].Hostname) {
+			if areOverlappingHostnames(httpsListeners[i].Hostname, httpsListeners[j].Hostname) {
 				// Overlapping listeners can be more than two, we only report the first two for simplicity.
 				overlappingListeners[i] = &overlappingListener{
 					gateway1:  httpsListeners[i].gateway,
@@ -398,7 +398,7 @@ type overlappingCertificate struct {
 func isOverlappingCertificate(cert1DNSNames, cert2DNSNames []string) *overlappingCertificate {
 	for _, dns1 := range cert1DNSNames {
 		for _, dns2 := range cert2DNSNames {
-			if isOverlappingHostname(ptr.To(gwapiv1.Hostname(dns1)), ptr.To(gwapiv1.Hostname(dns2))) {
+			if areOverlappingHostnames(ptr.To(gwapiv1.Hostname(dns1)), ptr.To(gwapiv1.Hostname(dns2))) {
 				return &overlappingCertificate{
 					san1: dns1,
 					san2: dns2,
@@ -409,22 +409,31 @@ func isOverlappingCertificate(cert1DNSNames, cert2DNSNames []string) *overlappin
 	return nil
 }
 
-// isOverlappingHostname checks if two hostnames overlap.
-func isOverlappingHostname(hostname1, hostname2 *gwapiv1.Hostname) bool {
-	if hostname1 == nil || hostname2 == nil {
+func areOverlappingHostnames(this, other *gwapiv1.Hostname) bool {
+	if this == nil || other == nil {
 		return true
 	}
-	domain1 := strings.Replace(string(*hostname1), "*.", "", 1)
-	domain2 := strings.Replace(string(*hostname2), "*.", "", 1)
-	return isSubdomain(domain1, domain2) || isSubdomain(domain2, domain1)
+	return hostnameMatchesWithOther(this, other) || hostnameMatchesWithOther(other, this)
 }
 
-// isSubdomain checks if subDomain is a sub-domain of domain
-func isSubdomain(subDomain, domain string) bool {
-	if subDomain == domain {
-		return true
+// hostnameMatchesWithOther returns true if this hostname matches other hostname.
+// Assumes that hostnames will either be fully qualified or a wildcard hostname prefixed with a single wildcard.
+// E.g. "*.*.example.com" is not valid.
+func hostnameMatchesWithOther(this, other *gwapiv1.Hostname) bool {
+	thisString := string(*this)
+	otherString := string(*other)
+	if hasWildcardPrefix(other) && !hasWildcardPrefix(this) {
+		return strings.HasSuffix(thisString, otherString[1:]) &&
+			!strings.Contains(strings.TrimSuffix(thisString, otherString[1:]), ".") // not a subdomain
+	}
+	return thisString == otherString
+}
+
+func hasWildcardPrefix(h *gwapiv1.Hostname) bool {
+	if h == nil {
+		return false
 	}
-	return strings.HasSuffix(subDomain, fmt.Sprintf(".%s", domain))
+	return len(string(*h)) > 1 && string(*h)[0] == '*'
 }
 
 func buildListenerMetadata(listener *ListenerContext, gateway *GatewayContext) *ir.ResourceMetadata {
diff --git a/release-notes/current.yaml b/release-notes/current.yaml
index 8a55f9b90..f9db2e5b3 100644
--- a/release-notes/current.yaml
+++ b/release-notes/current.yaml
@@ -38,6 +38,7 @@ bug fixes: |
   Fixed a nil pointer panic in the XDS translator when building API key authentication filter configurations with `sanitize` enabled and no `forwardClientIDHeader` set.
   Truncated Gateway API status condition messages to stay within Kubernetes limits and prevent update failures.
   Fixed an issue in EnvoyPatchPolicy where it didn't match the target Gateway/GatewayClass due to an incorrect name reference.
+  Fixed certificate SAN overlap detection in gateway listeners.
 
 # Enhancements that improve performance.
 performance improvements: |
diff --git a/site/content/en/v1.0/tasks/security/mutual-tls.md b/site/content/en/v1.0/tasks/security/mutual-tls.md
index c57b6f8b2..b56e60c04 100644
--- a/site/content/en/v1.0/tasks/security/mutual-tls.md
+++ b/site/content/en/v1.0/tasks/security/mutual-tls.md
@@ -147,4 +147,28 @@ curl -v -HHost:www.example.com --resolve "www.example.com:443:${GATEWAY_HOST}" \
 --cacert example.com.crt https://www.example.com/get
 ```
 
+## Clean-Up
+
+Follow the steps from the [Quickstart](../../quickstart) to uninstall Envoy Gateway and the example manifest.
+
+Delete the ClientTrafficPolicy and the secrets:
+
+```shell
+kubectl delete clienttrafficpolicy/enable-mtls
+kubectl delete secret/example-cert
+kubectl delete secret/example-ca-cert
+```
+
+Delete the certificates and keys:
+
+```shell
+rm example.com.crt example.com.key
+rm www.example.com.crt www.example.com.key www.example.com.csr
+rm client.example.com.crt client.example.com.key client.example.com.csr
+```
+
+## Next Steps
+
+Checkout the [Developer Guide](../../../contributions/develop) to get involved in the project.
+
 [ClientTrafficPolicy]: ../../../api/extension_types#clienttrafficpolicy
diff --git a/site/content/en/v1.0/tasks/security/oidc.md b/site/content/en/v1.0/tasks/security/oidc.md
index c11a52bbf..1017c7e7a 100644
--- a/site/content/en/v1.0/tasks/security/oidc.md
+++ b/site/content/en/v1.0/tasks/security/oidc.md
@@ -313,7 +313,7 @@ kubectl delete httproute/myapp
 
 ## Next Steps
 
-Checkout the [Developer Guide](../../../../contributions/develop) to get involved in the project.
+Checkout the [Developer Guide](../../../contributions/develop) to get involved in the project.
 
 [oidc]: https://openid.net/connect/
 [google-oidc]: https://developers.google.com/identity/protocols/oauth2/openid-connect
diff --git a/site/content/en/v1.1/tasks/security/mutual-tls.md b/site/content/en/v1.1/tasks/security/mutual-tls.md
index 8a28d0d36..43336f161 100644
--- a/site/content/en/v1.1/tasks/security/mutual-tls.md
+++ b/site/content/en/v1.1/tasks/security/mutual-tls.md
@@ -181,4 +181,28 @@ curl -v -HHost:www.example.com --resolve "www.example.com:8443:127.0.0.1" \
 {{% /tab %}}
 {{< /tabpane >}}
 
+## Clean-Up
+
+Follow the steps from the [Quickstart](../../quickstart) to uninstall Envoy Gateway and the example manifest.
+
+Delete the ClientTrafficPolicy and the secrets:
+
+```shell
+kubectl delete clienttrafficpolicy/enable-mtls
+kubectl delete secret/example-cert
+kubectl delete secret/example-ca-cert
+```
+
+Delete the certificates and keys:
+
+```shell
+rm example.com.crt example.com.key
+rm www.example.com.crt www.example.com.key www.example.com.csr
+rm client.example.com.crt client.example.com.key client.example.com.csr
+```
+
+## Next Steps
+
+Checkout the [Developer Guide](../../../contributions/develop) to get involved in the project.
+
 [ClientTrafficPolicy]: ../../../api/extension_types#clienttrafficpolicy
diff --git a/site/content/en/v1.1/tasks/security/oidc.md b/site/content/en/v1.1/tasks/security/oidc.md
index 5110cc974..06dc65c4d 100644
--- a/site/content/en/v1.1/tasks/security/oidc.md
+++ b/site/content/en/v1.1/tasks/security/oidc.md
@@ -313,7 +313,7 @@ kubectl delete httproute/myapp
 
 ## Next Steps
 
-Checkout the [Developer Guide](../../../../contributions/develop) to get involved in the project.
+Checkout the [Developer Guide](../../../contributions/develop) to get involved in the project.
 
 [oidc]: https://openid.net/connect/
 [google-oidc]: https://developers.google.com/identity/protocols/oauth2/openid-connect
diff --git a/site/content/en/v1.2/tasks/security/mutual-tls.md b/site/content/en/v1.2/tasks/security/mutual-tls.md
index 4ac9f9643..bd3846dd3 100644
--- a/site/content/en/v1.2/tasks/security/mutual-tls.md
+++ b/site/content/en/v1.2/tasks/security/mutual-tls.md
@@ -180,4 +180,28 @@ curl -v -HHost:www.example.com --resolve "www.example.com:8443:127.0.0.1" \
 {{% /tab %}}
 {{< /tabpane >}}
 
+## Clean-Up
+
+Follow the steps from the [Quickstart](../../quickstart) to uninstall Envoy Gateway and the example manifest.
+
+Delete the ClientTrafficPolicy and the secrets:
+
+```shell
+kubectl delete clienttrafficpolicy/enable-mtls
+kubectl delete secret/example-cert
+kubectl delete secret/example-ca-cert
+```
+
+Delete the certificates and keys:
+
+```shell
+rm example.com.crt example.com.key
+rm www.example.com.crt www.example.com.key www.example.com.csr
+rm client.example.com.crt client.example.com.key client.example.com.csr
+```
+
+## Next Steps
+
+Checkout the [Developer Guide](../../../contributions/develop) to get involved in the project.
+
 [ClientTrafficPolicy]: ../../../api/extension_types#clienttrafficpolicy
diff --git a/site/content/en/v1.2/tasks/security/oidc.md b/site/content/en/v1.2/tasks/security/oidc.md
index 53c1dcd6a..f64229a9a 100644
--- a/site/content/en/v1.2/tasks/security/oidc.md
+++ b/site/content/en/v1.2/tasks/security/oidc.md
@@ -552,7 +552,7 @@ kubectl delete httproute/foo
 
 ## Next Steps
 
-Checkout the [Developer Guide](../../../../contributions/develop) to get involved in the project.
+Checkout the [Developer Guide](../../../contributions/develop) to get involved in the project.
 
 [oidc]: https://openid.net/connect/
 [google-oidc]: https://developers.google.com/identity/protocols/oauth2/openid-connect
diff --git a/site/content/en/v1.3/tasks/security/mutual-tls.md b/site/content/en/v1.3/tasks/security/mutual-tls.md
index 4ac9f9643..bd3846dd3 100644
--- a/site/content/en/v1.3/tasks/security/mutual-tls.md
+++ b/site/content/en/v1.3/tasks/security/mutual-tls.md
@@ -180,4 +180,28 @@ curl -v -HHost:www.example.com --resolve "www.example.com:8443:127.0.0.1" \
 {{% /tab %}}
 {{< /tabpane >}}
 
+## Clean-Up
+
+Follow the steps from the [Quickstart](../../quickstart) to uninstall Envoy Gateway and the example manifest.
+
+Delete the ClientTrafficPolicy and the secrets:
+
+```shell
+kubectl delete clienttrafficpolicy/enable-mtls
+kubectl delete secret/example-cert
+kubectl delete secret/example-ca-cert
+```
+
+Delete the certificates and keys:
+
+```shell
+rm example.com.crt example.com.key
+rm www.example.com.crt www.example.com.key www.example.com.csr
+rm client.example.com.crt client.example.com.key client.example.com.csr
+```
+
+## Next Steps
+
+Checkout the [Developer Guide](../../../contributions/develop) to get involved in the project.
+
 [ClientTrafficPolicy]: ../../../api/extension_types#clienttrafficpolicy
diff --git a/site/content/en/v1.3/tasks/security/oidc.md b/site/content/en/v1.3/tasks/security/oidc.md
index d4be436f0..d922ed45e 100644
--- a/site/content/en/v1.3/tasks/security/oidc.md
+++ b/site/content/en/v1.3/tasks/security/oidc.md
@@ -556,7 +556,7 @@ kubectl delete httproute/foo
 
 ## Next Steps
 
-Checkout the [Developer Guide](../../../../contributions/develop) to get involved in the project.
+Checkout the [Developer Guide](../../../contributions/develop) to get involved in the project.
 
 [oidc]: https://openid.net/connect/
 [google-oidc]: https://developers.google.com/identity/protocols/oauth2/openid-connect
diff --git a/site/content/en/v1.4/tasks/security/mutual-tls.md b/site/content/en/v1.4/tasks/security/mutual-tls.md
index 4ac9f9643..bd3846dd3 100644
--- a/site/content/en/v1.4/tasks/security/mutual-tls.md
+++ b/site/content/en/v1.4/tasks/security/mutual-tls.md
@@ -180,4 +180,28 @@ curl -v -HHost:www.example.com --resolve "www.example.com:8443:127.0.0.1" \
 {{% /tab %}}
 {{< /tabpane >}}
 
+## Clean-Up
+
+Follow the steps from the [Quickstart](../../quickstart) to uninstall Envoy Gateway and the example manifest.
+
+Delete the ClientTrafficPolicy and the secrets:
+
+```shell
+kubectl delete clienttrafficpolicy/enable-mtls
+kubectl delete secret/example-cert
+kubectl delete secret/example-ca-cert
+```
+
+Delete the certificates and keys:
+
+```shell
+rm example.com.crt example.com.key
+rm www.example.com.crt www.example.com.key www.example.com.csr
+rm client.example.com.crt client.example.com.key client.example.com.csr
+```
+
+## Next Steps
+
+Checkout the [Developer Guide](../../../contributions/develop) to get involved in the project.
+
 [ClientTrafficPolicy]: ../../../api/extension_types#clienttrafficpolicy
diff --git a/site/content/en/v1.4/tasks/security/oidc.md b/site/content/en/v1.4/tasks/security/oidc.md
index d4be436f0..d922ed45e 100644
--- a/site/content/en/v1.4/tasks/security/oidc.md
+++ b/site/content/en/v1.4/tasks/security/oidc.md
@@ -556,7 +556,7 @@ kubectl delete httproute/foo
 
 ## Next Steps
 
-Checkout the [Developer Guide](../../../../contributions/develop) to get involved in the project.
+Checkout the [Developer Guide](../../../contributions/develop) to get involved in the project.
 
 [oidc]: https://openid.net/connect/
 [google-oidc]: https://developers.google.com/identity/protocols/oauth2/openid-connect
diff --git a/site/content/en/v1.5/tasks/security/mutual-tls.md b/site/content/en/v1.5/tasks/security/mutual-tls.md
index 4ac9f9643..bd3846dd3 100644
--- a/site/content/en/v1.5/tasks/security/mutual-tls.md
+++ b/site/content/en/v1.5/tasks/security/mutual-tls.md
@@ -180,4 +180,28 @@ curl -v -HHost:www.example.com --resolve "www.example.com:8443:127.0.0.1" \
 {{% /tab %}}
 {{< /tabpane >}}
 
+## Clean-Up
+
+Follow the steps from the [Quickstart](../../quickstart) to uninstall Envoy Gateway and the example manifest.
+
+Delete the ClientTrafficPolicy and the secrets:
+
+```shell
+kubectl delete clienttrafficpolicy/enable-mtls
+kubectl delete secret/example-cert
+kubectl delete secret/example-ca-cert
+```
+
+Delete the certificates and keys:
+
+```shell
+rm example.com.crt example.com.key
+rm www.example.com.crt www.example.com.key www.example.com.csr
+rm client.example.com.crt client.example.com.key client.example.com.csr
+```
+
+## Next Steps
+
+Checkout the [Developer Guide](../../../contributions/develop) to get involved in the project.
+
 [ClientTrafficPolicy]: ../../../api/extension_types#clienttrafficpolicy
diff --git a/site/content/en/v1.5/tasks/security/oidc.md b/site/content/en/v1.5/tasks/security/oidc.md
index d4be436f0..d922ed45e 100644
--- a/site/content/en/v1.5/tasks/security/oidc.md
+++ b/site/content/en/v1.5/tasks/security/oidc.md
@@ -556,7 +556,7 @@ kubectl delete httproute/foo
 
 ## Next Steps
 
-Checkout the [Developer Guide](../../../../contributions/develop) to get involved in the project.
+Checkout the [Developer Guide](../../../contributions/develop) to get involved in the project.
 
 [oidc]: https://openid.net/connect/
 [google-oidc]: https://developers.google.com/identity/protocols/oauth2/openid-connect



Test patch:
diff --git a/internal/gatewayapi/listener_test.go b/internal/gatewayapi/listener_test.go
index 520cb2305..f10b93148 100644
--- a/internal/gatewayapi/listener_test.go
+++ b/internal/gatewayapi/listener_test.go
@@ -100,7 +100,7 @@ func TestProxySamplingRate(t *testing.T) {
 	}
 }
 
-func TestIsOverlappingHostname(t *testing.T) {
+func TestAreOverlappingHostnames(t *testing.T) {
 	tests := []struct {
 		name      string
 		hostname1 *gwapiv1.Hostname
@@ -120,10 +120,10 @@ func TestIsOverlappingHostname(t *testing.T) {
 			want:      true,
 		},
 		{
-			name:      "two wildcards matches subdomain",
+			name:      "two wildcards with subdomain does not match",
 			hostname1: ptr.To(gwapiv1.Hostname("*.example.com")),
 			hostname2: ptr.To(gwapiv1.Hostname("*.test.example.com")),
-			want:      true,
+			want:      false,
 		},
 		{
 			name:      "nil hostname matches all",
@@ -144,22 +144,22 @@ func TestIsOverlappingHostname(t *testing.T) {
 			want:      true,
 		},
 		{
-			name:      "wildcard matches exact",
+			name:      "wildcard matches exactly one level of subdomain",
 			hostname1: ptr.To(gwapiv1.Hostname("*.example.com")),
 			hostname2: ptr.To(gwapiv1.Hostname("test.example.com")),
 			want:      true,
 		},
 		{
-			name:      "wildcard matches subdomain",
+			name:      "wildcard matches only one level of subdomain",
 			hostname1: ptr.To(gwapiv1.Hostname("*.example.com")),
 			hostname2: ptr.To(gwapiv1.Hostname("sub.test.example.com")),
-			want:      true,
+			want:      false,
 		},
 		{
-			name:      "wildcard matches empty subdomain",
+			name:      "wildcard does not match empty subdomain",
 			hostname1: ptr.To(gwapiv1.Hostname("*.example.com")),
 			hostname2: ptr.To(gwapiv1.Hostname("example.com")),
-			want:      true,
+			want:      false,
 		},
 		{
 			name:      "different domains",
@@ -185,15 +185,21 @@ func TestIsOverlappingHostname(t *testing.T) {
 			hostname2: ptr.To(gwapiv1.Hostname("testing-api.foo.dev")),
 			want:      false,
 		},
+		{
+			name:      "sub domain does not match with parent domain",
+			hostname1: ptr.To(gwapiv1.Hostname("api.foo.dev")),
+			hostname2: ptr.To(gwapiv1.Hostname("foo.dev")),
+			want:      false,
+		},
 	}
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			if got := isOverlappingHostname(tt.hostname1, tt.hostname2); got != tt.want {
+			if got := areOverlappingHostnames(tt.hostname1, tt.hostname2); got != tt.want {
 				t.Errorf("isOverlappingHostname(%q, %q) = %v, want %v", ptr.Deref(tt.hostname1, ""), ptr.Deref(tt.hostname2, ""), got, tt.want)
 			}
 			// Test should be symmetric
-			if got := isOverlappingHostname(tt.hostname2, tt.hostname1); got != tt.want {
+			if got := areOverlappingHostnames(tt.hostname2, tt.hostname1); got != tt.want {
 				t.Errorf("isOverlappingHostname(%q, %q) = %v, want %v", ptr.Deref(tt.hostname2, ""), ptr.Deref(tt.hostname1, ""), got, tt.want)
 			}
 		})
@@ -306,7 +312,7 @@ func TestCheckOverlappingHostnames(t *testing.T) {
 							Name:     "listener-3",
 							Protocol: gwapiv1.HTTPSProtocolType,
 							Port:     443,
-							Hostname: ptr.To(gwapiv1.Hostname("sub.test.example.com")),
+							Hostname: ptr.To(gwapiv1.Hostname("sub.test.example.com")), // sub domain does not match with parent domain
 						},
 					},
 				},
@@ -314,7 +320,6 @@ func TestCheckOverlappingHostnames(t *testing.T) {
 			expected: map[int]string{
 				0: "test.example.com",
 				1: "*.example.com",
-				2: "*.example.com",
 			},
 		},
 		{
diff --git a/site/content/en/latest/tasks/security/mutual-tls.md b/site/content/en/latest/tasks/security/mutual-tls.md
index 4ac9f9643..bd3846dd3 100644
--- a/site/content/en/latest/tasks/security/mutual-tls.md
+++ b/site/content/en/latest/tasks/security/mutual-tls.md
@@ -180,4 +180,28 @@ curl -v -HHost:www.example.com --resolve "www.example.com:8443:127.0.0.1" \
 {{% /tab %}}
 {{< /tabpane >}}
 
+## Clean-Up
+
+Follow the steps from the [Quickstart](../../quickstart) to uninstall Envoy Gateway and the example manifest.
+
+Delete the ClientTrafficPolicy and the secrets:
+
+```shell
+kubectl delete clienttrafficpolicy/enable-mtls
+kubectl delete secret/example-cert
+kubectl delete secret/example-ca-cert
+```
+
+Delete the certificates and keys:
+
+```shell
+rm example.com.crt example.com.key
+rm www.example.com.crt www.example.com.key www.example.com.csr
+rm client.example.com.crt client.example.com.key client.example.com.csr
+```
+
+## Next Steps
+
+Checkout the [Developer Guide](../../../contributions/develop) to get involved in the project.
+
 [ClientTrafficPolicy]: ../../../api/extension_types#clienttrafficpolicy
diff --git a/site/content/en/latest/tasks/security/oidc.md b/site/content/en/latest/tasks/security/oidc.md
index d4be436f0..d922ed45e 100644
--- a/site/content/en/latest/tasks/security/oidc.md
+++ b/site/content/en/latest/tasks/security/oidc.md
@@ -556,7 +556,7 @@ kubectl delete httproute/foo
 
 ## Next Steps
 
-Checkout the [Developer Guide](../../../../contributions/develop) to get involved in the project.
+Checkout the [Developer Guide](../../../contributions/develop) to get involved in the project.
 
 [oidc]: https://openid.net/connect/
 [google-oidc]: https://developers.google.com/identity/protocols/oauth2/openid-connect