Mar 20, 2026·6 min read·37 visits
A flaw in Traefik's custom SNI pre-sniffing logic allows unauthenticated attackers to bypass route-specific mTLS requirements by transmitting a artificially fragmented TLS ClientHello message.
Traefik versions up to 2.11.40 and 3.6.10 are vulnerable to a mutual TLS (mTLS) bypass. The vulnerability occurs in the TLS Server Name Indication (SNI) pre-sniffing logic when handling fragmented ClientHello packets. This extraction failure results in the proxy falling back to a global default TLS configuration, which allows attackers to bypass route-level mTLS authentication requirements.
Traefik operates as a widely deployed HTTP reverse proxy and load balancer. A core security feature of Traefik is the ability to enforce mutual TLS (mTLS) authentication on specific routing paths. This feature ensures that only clients presenting a cryptographically valid certificate can access protected internal upstream services.
CVE-2026-32305 is classified as an Improper Authentication (CWE-287) and Insecure Default Initialization of Resource (CWE-1188) vulnerability. The flaw exists entirely within Traefik's custom connection sniffing logic. This logic is used to route incoming TLS connections before the formal cryptographic handshake is completed by the standard library.
When processing incoming TLS packets, Traefik attempts to extract the Server Name Indication (SNI) extension early in the connection lifecycle. If this early extraction fails, Traefik silently falls back to a global default TLS configuration. An attacker can manipulate this behavior to bypass route-specific mTLS constraints completely.
The vulnerability is isolated to the ServeTCP function located within router.go. Traefik attempts to "pre-sniff" the SNI from the incoming connection to determine which specific TLS configuration and routing rules to apply. This pre-sniffing process relies on the internal clientHelloInfo function to peek at the initial bytes of the connection stream without consuming them.
The sniffing logic evaluates the first TLS record to read its length, which is temporarily stored as recLen. It then attempts to read exactly 5 + recLen bytes to parse the entire ClientHello message into a readable structure. This implementation assumes that the complete ClientHello message fits within a single contiguous TLS record, a common behavior that is not strictly mandated by the TLS protocol specification.
If a client transmits a ClientHello that is explicitly fragmented across multiple TLS records, the peeked data segment is incomplete. The custom TLS parser encounters an unexpected end of data and throws an EOF error. As a direct result of the unhandled error state, the parser returns an empty string for the SNI value.
Because the SNI string evaluates as empty, the Traefik routing engine cannot match the incoming request to a specific, host-based routing rule during the pre-sniffing phase. Traefik resolves this undetermined routing state by applying the global default TLS configuration. If this default configuration is configured as NoClientCert, the subsequent standard Go standard library TLS handshake proceeds without requesting or verifying a client certificate.
Exploitation requires an attacker to deliberately fragment their initial TLS handshake. The attacker initiates a standard TCP connection to the Traefik entrypoint and begins the TLS handshake sequence. Instead of transmitting a standard ClientHello message within a single record, the attacker limits the maximum record size to split the message into multiple smaller cryptographic records.
The fragmentation boundaries must be specifically aligned so that the SNI extension data falls entirely outside the first TLS record. When Traefik processes this manipulated connection, the EOF error is reliably triggered within the pre-sniffing phase. The connection stream is then handed over to the standard Go crypto/tls library for the actual cryptographic handshake.
from tlsfuzzer.runner import Runner
from tlsfuzzer.messages import Connect, SetMaxRecordSize, ClientHelloGenerator
# ... standard tlsfuzzer imports omitted for brevity
def main():
# Set an artificially small record size to force fragmentation
record_size = 500
sni = "protected-service.internal"
conv = Connect("127.0.0.1", 8443)
node = conv.add_child(SetMaxRecordSize(record_size))
# SNI extension pushed beyond the initial record size limit
ext = {
ExtensionType.server_name: SNIExtension().create(bytearray(sni, "ascii")),
}
node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
node = node.add_child(ExpectServerHello())
Runner(conv).run()Once the standard Go library assumes control of the connection socket, it successfully reads the remaining records, reassembles the fragmented ClientHello, and completes the handshake using the fallback permissive TLS policy. After the secure channel is established, the attacker transmits an HTTP request specifying a Host header that targets the protected internal service. Traefik processes the authorized HTTP request and routes it to the backend, completely bypassing the intended route-level mTLS enforcement.
The vulnerability carries a CVSS v4.0 base score of 7.8, reflecting a high severity security defect combined with a low attack complexity. The attack requires absolutely no prior authentication, requires no user interaction, and can be executed remotely from any position with network access to the proxy listener.
The primary security consequence is a complete bypass of intended authentication and access controls for the affected routing paths. Organizations relying on Traefik as an edge ingress controller to enforce Zero Trust network access parameters via mTLS are directly exposed. Attackers can reach internal microservices, administrative interfaces, or sensitive data stores that architectural models assumed to be cryptographically isolated.
While the vulnerability permits unauthorized routing to protected endpoints, the ultimate impact on system confidentiality and integrity depends entirely on the security posture of the exposed backend services. Traefik itself is not compromised, nor does this flaw provide a direct vector for remote code execution on the underlying proxy host system.
The maintainers addressed the core issue in Traefik versions 2.11.41, 3.6.11, and 3.7.0-ea.2. The security patch fundamentally alters the initial connection handling logic to correctly process multi-record ClientHello messages. The fix implemented in Pull Request #12787 delegates the fragmented record processing directly to the robust Go standard library, rather than relying on brittle custom byte-peeking logic.
If immediate software patching is not feasible, system administrators must alter the global default TLS configuration as a compensating control. The default policy must be explicitly hardened to enforce mTLS globally utilizing the RequireAndVerifyClientCert directive. This ensures that any routing failure resulting in an empty SNI correctly defaults to a restrictive security posture rather than a permissive one.
tls:
options:
default:
clientAuth:
caFiles:
- /path/to/ca.crt
clientAuthType: RequireAndVerifyClientCertImplementing this specific configuration workaround requires administrators to explicitly define permissive TLS options (NoClientCert) for all intended public-facing routes. This inverts the proxy's default behavior and establishes a fail-closed security architecture. Network security monitoring systems should also be configured to generate alerts for heavily fragmented TLS ClientHello packets.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Traefik Traefik Labs | <= 2.11.40 | 2.11.41 |
Traefik Traefik Labs | >= 3.0.0-beta1, <= 3.6.10 | 3.6.11 |
Traefik Traefik Labs | = 3.7.0-ea.1 | 3.7.0-ea.2 |
| Attribute | Detail |
|---|---|
| Attack Vector | Network |
| CWE ID | CWE-287, CWE-1188 |
| CVSS v4.0 | 7.8 |
| EPSS Score | 0.00046 (13.81%) |
| Exploit Status | Proof-of-Concept Available |
| KEV Status | Not Listed |
Improper Authentication and Insecure Default Initialization of Resource resulting in mTLS bypass.
The @jhb.software/payload-cloudinary-plugin exposes an endpoint that performs unvalidated cryptographic signing of Cloudinary API parameters, allowing authenticated users with minimal privileges to forge valid signatures for arbitrary actions. This flaw allows attackers to overwrite remote storage assets, execute unauthorized file uploads, alter asset visibility parameters, trigger SSRF webhooks, and perform directory traversal within Cloudinary repositories.
A Server-Side Request Forgery (SSRF) and Bearer Token Exfiltration vulnerability exists in the @merill/lokka (Lokka) Model Context Protocol (MCP) server prior to version 2.1.2. The server constructed Azure Resource Manager request URLs by concatenating user-controlled path parameters directly into destination request strings. By injecting authority-redefinition characters, an attacker can manipulate URL parsing to execute a host-escape attack, forcing the server to send high-privilege Azure Resource Manager (ARM) Bearer tokens to an external attacker-controlled host. This allows complete administrative access to the associated Azure subscriptions.
A directory traversal and symlink following vulnerability exists in Pydantic Settings when using the NestedSecretsSettingsSource with nested subdirectory lookups enabled. An attacker capable of writing to the secrets directory can bypass size limitations, read arbitrary host files, or cause a denial-of-service condition via cyclic symlinks.
A Server-Side Request Forgery (SSRF) vulnerability exists in SurrealDB's Identity & Access Management (IAM) module prior to version 3.1.5. When configuring JSON Web Key Set (JWKS) URLs for token verification, the remote fetcher follows HTTP redirects by default without validating redirect targets against configured network capabilities. This allows high-privileged users to bypass network access limits and perform blind port scanning of internal network resources.
A local file disclosure vulnerability exists in SurrealDB's full-text search capabilities, allowing authenticated users with database EDITOR or OWNER roles to read arbitrary files from the host system filesystem. This occurs by abusing the mapper() filter inside a DEFINE ANALYZER statement to point to system files.
SurrealDB versions 3.0.0 through 3.1.4 contain an information exposure vulnerability (CWE-203) where the query planner optimizes sorted queries using indexes on fields with field-level SELECT restrictions. Because the query planner performs index-based sorting before enforcing permission-based redaction, unauthorized users can observe the physical order of returned rows to deduce the relative values of protected fields.