Original Description
Summary
A logic error in Traefik's experimental ingress-nginx provider inverts the semantics of the nginx.ingress.kubernetes.io/proxy-ssl-verify annotation. Setting the annotation to "on" (intending to enable backend TLS certificate verification) actually disables verification, allowing man-in-the-middle attacks against HTTPS backends when operators believe they are protected.
Details
In pkg/provider/kubernetes/ingress-nginx/kubernetes.go at line 512, the InsecureSkipVerify field is set using inverted logic:
nst := &namedServersTransport{
Name: provider.Normalize(namespace + "-" + name),
ServersTransport: &dynamic.ServersTransport{
ServerName: ptr.Deref(cfg.ProxySSLName, ptr.Deref(cfg.ProxySSLServerName, "")),
InsecureSkipVerify: strings.ToLower(ptr.Deref(cfg.ProxySSLVerify, "off")) == "on",
},
}
The expression == "on" evaluates to true when the annotation is "on", setting InsecureSkipVerify: true. In Go's crypto/tls, InsecureSkipVerify: true means "do not verify the server's certificate" — the opposite of what proxy-ssl-verify: "on" should do according to NGINX semantics.
Current behavior:
| Annotation Value |
InsecureSkipVerify |
Actual Result |
"on" |
true |
Verification disabled ❌ |
"off" (default) |
false |
Verification enabled |
Expected behavior (per NGINX semantics):
| Annotation Value |
InsecureSkipVerify |
Expected Result |
"on" |
false |
Verification enabled |
"off" (default) |
true |
Verification disabled |
The test in pkg/provider/kubernetes/ingress-nginx/kubernetes_test.go lines 397-403 confirms this inverted behavior is codified as "expected":
ServersTransports: map[string]*dynamic.ServersTransport{
"default-ingress-with-proxy-ssl": {
ServerName: "whoami.localhost",
InsecureSkipVerify: true, // Wrong: should be false when annotation is "on"
RootCAs: []types.FileOrContent{"-----BEGIN CERTIFICATE-----"},
},
},
Affected versions: v3.5.0 through current master (introduced in commit 9bd5c617820f2a8d23b50b68d114bb7bc464eccd)
Pavel Kohout
Aisle Research
Impact
There is a potential vulnerability in Traefik NGINX provider managing the
nginx.ingress.kubernetes.io/proxy-ssl-verifyannotation.The provider inverts the semantics of the
nginx.ingress.kubernetes.io/proxy-ssl-verifyannotation. Setting the annotation to"on"(intending to enable backend TLS certificate verification) actually disables verification, allowing man-in-the-middle attacks against HTTPS backends when operators believe they are protected.Patches
For more information
If you have any questions or comments about this advisory, please open an issue.
Original Description
Summary
A logic error in Traefik's experimental ingress-nginx provider inverts the semantics of the
nginx.ingress.kubernetes.io/proxy-ssl-verifyannotation. Setting the annotation to"on"(intending to enable backend TLS certificate verification) actually disables verification, allowing man-in-the-middle attacks against HTTPS backends when operators believe they are protected.Details
In
pkg/provider/kubernetes/ingress-nginx/kubernetes.goat line 512, theInsecureSkipVerifyfield is set using inverted logic:The expression
== "on"evaluates totruewhen the annotation is"on", settingInsecureSkipVerify: true. In Go'scrypto/tls,InsecureSkipVerify: truemeans "do not verify the server's certificate" — the opposite of whatproxy-ssl-verify: "on"should do according to NGINX semantics.Current behavior:
"on"true"off"(default)falseExpected behavior (per NGINX semantics):
"on"false"off"(default)trueThe test in
pkg/provider/kubernetes/ingress-nginx/kubernetes_test.golines 397-403 confirms this inverted behavior is codified as "expected":Affected versions: v3.5.0 through current master (introduced in commit
9bd5c617820f2a8d23b50b68d114bb7bc464eccd)Pavel Kohout
Aisle Research
References