CVE-2025-66491: Traefik's "Verify=On" Turned TLS Off

Author

AISLE Research Team

Published

traefik-bg

See what AISLE can find and fix autonomously in your own code.

Sovereign AI CybersecurityTalk to Us

A semantic mismatch in Traefik's experimental ingress-nginx provider inverted TLS verification for five months.

Traefik is one of the most popular cloud-native reverse proxies and ingress controllers in the world. With over 60,000 GitHub stars and more than 3 billion downloads, it routes traffic for countless production systems: financial services, healthcare platforms, SaaS products, and internal control planes across enterprises of every size. When you configure Traefik, you're often configuring the front door to your entire infrastructure.

Our autonomous analyzer, operated by Pavel Kohout of AISLE Research, discovered that Traefik's experimental ingress-nginx provider inverted the semantics of the nginx.ingress.kubernetes.io/proxy-ssl-verify annotation. Setting it to "on" (the NGINX convention for enabling verification) actually disabled TLS certificate verification, exposing HTTPS backends to man-in-the-middle attacks. In Kubernetes, annotations function as policy at scale: a single line can govern thousands of routes across an entire organization. This one word, intended to harden security, did the opposite.

This issue is tracked as CVE-2025-66491 (CWE-295: Improper Certificate Validation). It affected Traefik versions v3.5.0 through v3.6.2 and was fixed in v3.6.3. The bug lived in the codebase for approximately five months, from the provider's introduction on June 23, 2025 until the fix on December 3, 2025.

The scale of Traefik

Traefik sits at the critical path of modern infrastructure. It handles:

  • Ingress traffic for Kubernetes clusters running in AWS, GCP, Azure, and on-premises data centers
  • Service mesh routing as part of Traefik Mesh deployments
  • API gateway functions for microservices architectures
  • Load balancing across containers, VMs, and serverless functions

The project is backed by Traefik Labs and used by organizations ranging from startups to Fortune 500 companies. Any vulnerability in Traefik's TLS handling has the potential to affect a vast number of systems. The ingress-nginx provider specifically targets teams migrating from NGINX Ingress Controller, meaning it serves security-conscious operators who explicitly configured backend certificate verification.

What we found

The ingress-nginx provider translates NGINX-style annotations into Traefik's internal configuration. The annotation nginx.ingress.kubernetes.io/proxy-ssl-verify tells the ingress controller whether to verify TLS certificates when proxying to HTTPS backends. In NGINX, "on" means "verify the backend certificate" and "off" means "skip verification."

Go's crypto/tls package uses a field called InsecureSkipVerify. When this field is true, verification is skipped. When it is false, verification is performed. The names point in opposite directions: NGINX's verify is a positive assertion, while Go's InsecureSkipVerify is a negative one.

The provider's code at pkg/provider/kubernetes/ingress-nginx/kubernetes.go line 512 contained this logic:

JavaScript
1nst := &namedServersTransport{
2 Name: provider.Normalize(namespace + "-" + name),
3 ServersTransport: &dynamic.ServersTransport{
4 ServerName: ptr.Deref(cfg.ProxySSLName, ptr.Deref(cfg.ProxySSLServerName, "")),
5 InsecureSkipVerify: strings.ToLower(ptr.Deref(cfg.ProxySSLVerify, "off")) == "on",
6 },
7}

The expression == "on" evaluates to true when the annotation is set to "on". That sets InsecureSkipVerify: true, which disables verification. The mapping was exactly inverted:

The unit test suite unintentionally encoded this inverted behavior as the expected outcome. The test fixture at pkg/provider/kubernetes/ingress-nginx/fixtures/ingresses/07-ingress-with-proxy-ssl.yml set proxy-ssl-verify: "on", and the test at pkg/provider/kubernetes/ingress-nginx/kubernetes_test.go expected InsecureSkipVerify: true:

JavaScript
1ServersTransports: map[string]*dynamic.ServersTransport{
2 "default-ingress-with-proxy-ssl": {
3 ServerName: "whoami.localhost",
4 InsecureSkipVerify: true, // expected by the test when annotation is "on"
5 RootCAs: []types.FileOrContent{"-----BEGIN CERTIFICATE-----"},
6 },
7},

This meant the bug passed CI. A test that looked like it was validating correct behavior was actually validating incorrect behavior. The test became a shield protecting the very flaw it was meant to prevent.

How trivial the bug was

The root cause was a single misplaced comparison operator. The entire vulnerability came down to this expression:

JavaScript
1InsecureSkipVerify: strings.ToLower(ptr.Deref(cfg.ProxySSLVerify, "off")) == "on"

That == "on" should have been == "off". One word. Three characters. That's the difference between "verify certificates" and "accept anything."

The fix (commit 14a1aedf5) was correspondingly simple. A single string changed:

JavaScript
1- InsecureSkipVerify: strings.ToLower(ptr.Deref(cfg.ProxySSLVerify, "off")) == "on",
2+ InsecureSkipVerify: strings.ToLower(ptr.Deref(cfg.ProxySSLVerify, "off")) == "off",

Now the logic correctly maps the annotation: when proxy-ssl-verify is "on", the expression == "off" evaluates to false, so InsecureSkipVerify is false, and verification is enabled. The test expectation was also updated from InsecureSkipVerify: true to InsecureSkipVerify: false.

Why this matters

The Kubernetes policy model at stake

Kubernetes standardizes control through declarative manifests. Annotations extend this model, letting operators express policy intent across clusters and namespaces with a single line of configuration. The ingress-nginx provider exists specifically to let teams migrate from NGINX Ingress Controller to Traefik while preserving their existing annotation-based policies.

When the annotation semantics are inverted, operators who set proxy-ssl-verify: "on" believing they are hardening their security are actually weakening it. They have no warning, no error, and no indication that their intent has been subverted.

Upstream TLS as the last line of defense

TLS verification between the ingress and backend services is often the last cryptographic checkpoint for east-west traffic within a cluster. If an attacker gains a network position between the ingress pod and a backend (through ARP spoofing, a compromised sidecar, or a misconfigured network policy), presenting a self-signed or invalid certificate should fail the connection. With InsecureSkipVerify: true, the attacker's certificate is accepted without question.

Once in this position, the attacker establishes an encrypted connection with Traefik while impersonating your backend. They can read every request in plaintext: user credentials, session tokens, API keys, and sensitive data. They can also modify responses, inject malicious content, or silently reroute traffic to a completely different service. The connection still appears encrypted to operators monitoring the cluster, making detection difficult.

This is particularly dangerous in multi-tenant Kubernetes environments, service meshes with optional mTLS, and any architecture where not all internal traffic is encrypted by the network layer.

The Boolean Mirage pattern

This bug exemplifies what we call the Boolean Mirage: a category of vulnerabilities where security intent expressed in one system gets inverted when translated to another system's primitives. The NGINX world says verify: on. The Go TLS world says InsecureSkipVerify: false. These two positives must meet, but without an explicit inversion step, they collide and produce the opposite of what was intended.

Why traditional scanners miss this

Traditional static analysis tools excel at finding certain patterns: buffer overflows, SQL injection, use-after-free, hardcoded credentials. They look for code that is syntactically or structurally dangerous. But this bug has none of those signatures. The code is clean:

  • No memory corruption
  • No injection points
  • No unsafe functions
  • No obviously wrong types
  • Compiles without warnings
  • Passes all tests

A conventional scanner sees a string comparison setting a boolean field. That's normal. That's fine. There's nothing to flag. The bug is invisible to tools that analyze code in isolation because the code is correct in isolation. The error exists only in the relationship between two systems: what NGINX annotations mean versus what Go TLS fields mean.

Our analyzer approaches this differently. Instead of pattern-matching against known vulnerability signatures, it builds a stack model of how security-relevant values flow through the system. It understands that proxy-ssl-verify is a policy input, that InsecureSkipVerify is a security-critical output, and that the mapping between them must preserve intent. When the semantics drift, when "on" becomes "skip," the analyzer flags the invariant violation. This is the difference between scanning for known bugs and reasoning about whether the code does what it should.

Affected versions and the fix

The ingress-nginx provider was introduced in v3.5.0-rc1 (June 23, 2025). The bug was present from the very first commit.

Release notes: Traefik v3.6.3

Severity assessment

CVSS 3.1 Score: 5.9 (Medium)

Vector: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N

In plain terms: An attacker who can position themselves in the network path between Traefik and a backend service can intercept HTTPS traffic that operators believed was protected by certificate verification. This requires network access (not just internet access) and typically means the attacker has already compromised some part of the infrastructure. The rating of "High" for Attack Complexity reflects this prerequisite. However, once that position is achieved, interception is straightforward.

Mitigating factors:

  • Only affects the experimental ingress-nginx provider
  • Requires explicit operator configuration (the annotation must be set)
  • The default value ("off") accidentally resulted in verification being enabled (secure by accident, insecure by intent)
  • Exploitation requires network positioning, not just remote access

Reproduction guide

  1. Deploy Traefik v3.5.0 through v3.6.2 with the experimental ingress-nginx provider enabled
  2. Create an Ingress resource with the following annotations:
JavaScript
1annotations:
2 nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
3 nginx.ingress.kubernetes.io/proxy-ssl-verify: "on"
4 nginx.ingress.kubernetes.io/proxy-ssl-secret: "<namespace>/<secret>"
  1. Configure a backend that presents an invalid or self-signed certificate (one that should fail verification)
  2. Send a request through Traefik to the backend
  3. Observe that the request succeeds despite the invalid certificate, because verification was disabled

Mitigation for operators

Upgrade to v3.6.3 as soon as possible. This is the only complete fix.

If you cannot upgrade immediately: The counterintuitive workaround is to set proxy-ssl-verify: "off" if you want verification enabled, or remove the annotation entirely. The default behavior in vulnerable versions accidentally enables verification when no annotation is present.

This inversion is exactly the bug. We document it here only for operators who cannot immediately upgrade. The fixed release restores intuitive behavior.

Timeline and disclosure

We appreciate the Traefik team's responsiveness and professionalism throughout the disclosure process. Their quick turnaround from report to fix demonstrates the kind of security-conscious development that makes open source infrastructure trustworthy.

The broader pattern

This vulnerability is a case study in cross-system semantic mapping. Provider bridges that translate configuration from one system (NGINX annotations) to another (Go TLS configuration) are security-critical glue code. They must handle:

  1. Naming conventions that differ: "verify" vs. "skip verify"
  2. Boolean polarities that oppose: positive assertion vs. negative assertion
  3. Default values that may not align: what happens when the annotation is absent?
  4. Test cases that may encode the wrong invariant: passing tests don't mean correct behavior

The Traefik maintainers have an excellent track record, and this provider was marked as experimental. The bug slipped through because the logic was locally reasonable (compare a string, set a boolean) but globally incorrect (the comparison inverted the intended semantics). This is the kind of glue-point error that our analyzer is designed to find: not broken code, but broken mappings between systems.

What makes this discovery notable is the combination of factors: a trivial bug (three characters), in critical infrastructure (3+ billion downloads), in a new and actively developed feature (not legacy code), that completely inverted security intent (verify became skip). The ingress-nginx provider was introduced just five months before we found this. It wasn't buried in ancient code that nobody looked at. It was fresh, reviewed, tested, and still wrong.

Acknowledgements

Thank you to the Traefik maintainers for their quick response, their commitment to security, and their continued work on an excellent project. The ingress-nginx provider makes migration easier for many teams, and this fix ensures it does so safely.

Learn more

Interested in AISLE's autonomous security platform? Visit aisle.com or reach out to [email protected].

Technical references:

Keep reading

More from AISLE

FeaturedResearchAISLE Discovered Six curl CVEs After OpenAI and Anthropic Found ZeroAfter frontier AI systems came up empty, AISLE surfaced six CVEs in curl, one of the world's most audited codebases. Its maintainers patched all six.Stanislav FortSeptember 2, 2026ResearchAISLE Discovers 6 High and Critical CVEs in FFmpegAISLE's AI-native engine found six high and critical CVEs in FFmpeg, including a 9.8 remote heap overflow and a stack overflow that survived 19 years.AISLE Research Team August 27, 2026ResearchAttackers Are Using AI to Find Vulnerabilities in Your Code. Your SAST Was Never Even Looking for ThemCan AI-native code analysis replace SAST, or is it just a complement. Here's what data from real-world results shows.Ondrej VlcekAugust 12, 2026ResearchAISLE Finds 21 Security Issues in FFmpeg, Including 6 New CVEsAISLE uncovered 21 issues in FFmpeg, including 6 new CVEs spanning code execution and out-of-bounds reads. All patched, with commit links inside.AISLE Research Team August 5, 2026ResearchAISLE Discovers a One-Click RCE Vulnerability in Cursor, VS Code, and Google AntigravityLearn how our AI found a one-click RCE vulnerability in 3 code editors: Cursor, VS Code, and Google Antigravity.Stanislav FortJuly 31, 2026ResearchThe Model That Fixes Your Code Might Hack the Linux KernelLearn how easy it is to trojanize a model, and what defenders can do to protect their supply chains from this emerging threat.Patrik MadaJuly 28, 2026PerspectivesThe Economics of Security Vulnerabilities: Why Discovery Is Not CommoditizingIf discovery is cheap, why are people willing to pay more for exploits than ever before? Here's what the market for exploits shows.Ondrej VlcekJuly 23, 2026ResearchAISLE Finds 8 CVEs Across MySQL, MariaDB, and PostgreSQLLearn how AISLE found 8 CVEs in critical databases using autonomous, AI-native analysis and verification.AISLE Research Team July 7, 2026ResearchAISLE Discovers 6 New CVEs in curl, Including the Oldest Issue Ever ReportedAISLE's analyzer discovered 6 new CVEs in curl, more than 2x the nearest AI security platform and including the oldest security issue in the project.AISLE Research Team June 24, 2026