Mar 20, 2026·6 min read·76 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.
CVE-2026-63349 is a critical privilege-dropping bypass vulnerability in the AnyIO asynchronous framework (versions 4.14.0 and 4.14.1) on POSIX platforms. Due to a variable assignment typo, supplementary groups specified by the developer are not correctly propagated to the execution backend, resulting in subprocesses retaining the parent process's elevated supplementary group permissions.
CVE-2026-63406 is an information disclosure vulnerability in AnyCable-go prior to version 1.6.15. The built-in telemetry client is enabled by default with a hardcoded public authentication token ('secret'). This client digests highly sensitive configuration parameters and command-line arguments, including JWT secrets and RPC secrets, into a stable SHA-256 fingerprint. This fingerprint is sent over public networks, exposing those administrative secrets to offline dictionary and brute-force attacks if intercepted.
CVE-2026-84992 is a Cross-Site Scripting (XSS) vulnerability affecting md-editor-v3 before version 6.5.4. It occurs because the fenced-code block language parser directly interpolates unescaped language metadata into unquoted HTML attributes inside the custom rendering callback. This bypasses the built-in XSSPlugin which runs during the parsing phase, before rendering.
CVE-2026-81505 is a high-severity Broken Object Level Authorization (BOLA) / Insecure Direct Object Reference (IDOR) vulnerability in Convoy, a cloud-native webhooks gateway. In affected versions prior to 26.6.8, the single-item Source retrieval API endpoint authorizes project access but fails to confirm if the requested Source belongs to that specific project. This logical flaw allows authenticated users or project-scoped API key holders to bypass tenant isolation boundaries and retrieve unredacted, plaintext message broker credentials for Apache Kafka, Amazon SQS, RabbitMQ, and Google Cloud Pub/Sub belonging to other tenants. This issue is fully patched in version 26.6.8.
CVE-2026-77339 is a critical security vulnerability in Process Compose before version 1.120.0. The Model Context Protocol (MCP) Server-Sent Events (SSE) listener transport subsystem fails to validate the HTTP Host and Origin headers, and does not enforce authentication. This omissions expose local loopback listeners to DNS rebinding attacks orchestrated by malicious remote websites visited by developers, enabling unauthorized process control and arbitrary command execution.
CVE-2026-77301 is a critical uncontrolled resource allocation vulnerability in the popular Node.js library adm-zip (versions prior to 0.6.1). During ZIP decompression of asynchronous entries, the library trusts the uncompressed size metadata declared in the central directory headers. Because Node.js's streaming zlib API completely ignores the maxOutputLength configuration, a crafted ZIP archive (decompression bomb) causes the application to continually allocate resident memory buffers on the heap without limits, causing rapid memory exhaustion and a process-level Out-of-Memory (OOM) crash.