Mar 30, 2026·6 min read·5 visits
Traefik and gRPC-Go fail to properly normalize HTTP/2 :path headers, allowing unauthenticated attackers to bypass authorization deny rules by omitting the leading slash in the request path.
A critical authorization bypass vulnerability exists in Traefik due to improper path normalization in its underlying gRPC-Go dependency (CVE-2026-33186). Unauthenticated attackers can bypass configured deny rules by sending maliciously crafted gRPC requests over HTTP/2 that omit the mandatory leading slash in the :path pseudo-header. This canonicalization mismatch allows unauthorized access to protected services.
Traefik relies on gRPC-Go to handle HTTP/2 gRPC traffic. The vulnerability, tracked as GHSA-46WH-3698-F2CX and CVE-2026-33186, resides in the path processing logic of the gRPC-Go server implementation. It allows unauthenticated remote attackers to bypass security policies, specifically deny rules, configured within Traefik or gRPC-Go interceptors.
The gRPC specification mandates that the HTTP/2 :path pseudo-header must follow the exact format /{service}/{method}. Vulnerable versions of gRPC-Go accept malformed requests where this leading slash is deliberately omitted. The server internal routing mechanism successfully dispatches these malformed requests to the intended service handlers.
Authorization interceptors operate under the strict assumption that the FullMethod string exactly matches the canonical gRPC format. Because the routing logic tolerates the missing slash but the authorization logic performs strict literal matching, a canonicalization mismatch occurs. This structural discrepancy allows malicious requests to evade deny rules while still successfully executing the underlying Remote Procedure Call.
The root cause is a classic interpretation conflict between the routing component and the authorization component within the gRPC request lifecycle. In gRPC-Go, the server.go implementation extracts the target method name directly from the HTTP/2 :path pseudo-header. Prior to version 1.79.3, the server logic identified the presence of a leading slash and explicitly stripped it before passing the string to the internal multiplexer.
If an attacker submits a request entirely lacking the leading slash, the stripping logic is bypassed entirely. However, the multiplexer still parses the string correctly based on the trailing slash separating the service and method names. The multiplexer successfully identifies the target service and method, continuing the execution flow without error.
Authorization interceptors, such as grpc/authz or Traefik's custom middleware, intercept the request prior to final handler execution. These interceptors evaluate security policies against the FullMethod field, which is populated directly from the raw :path header. Security policies are explicitly defined using canonical paths, such as DENY /InternalService/SensitiveMethod.
When a malformed request arrives with :path: InternalService/SensitiveMethod, the literal string comparison against the canonical DENY rule fails. The authorization interceptor concludes that the rule does not apply to the current request and erroneously grants access. The server subsequently routes the request to the handler, resulting in a complete bypass of the intended access controls.
The vulnerable implementation in google.golang.org/grpc resided in the stream initialization phase within server.go. The logic extracted the stream method and conditionally removed the leading slash without validating its required presence according to the gRPC specification.
// Vulnerable server.go logic
sm := stream.Method()
if sm != "" && sm[0] == '/' {
sm = sm[1:]
}
// Routing continues with 'sm'The pre-patch code extracted the method using sm := stream.Method(). It then checked if the string was non-empty and whether the first character was a slash. If true, it executed sm = sm[1:]. This permissive approach guaranteed that both canonical and malformed paths converged to the same internal representation for routing purposes, creating the condition for the authorization bypass.
The patch introduced in commit 72186f163e75a065c39e6f7df9b6dea07fbdeff5 replaces this permissive logic with strict validation. The handleStream function now explicitly verifies the presence of the leading slash and rejects non-conformant requests immediately.
// Patched server.go logic
sm := stream.Method()
if sm == "" {
s.handleMalformedMethodName(stream, ti)
return
}
if sm[0] != '/' {
s.handleMalformedMethodName(stream, ti)
return
}The patched logic evaluates if sm[0] != '/' and routes the request to s.handleMalformedMethodName(stream, ti) if the condition is met. This ensures that the gRPC-Go server fundamentally rejects HTTP/2 frames that violate the gRPC specification before authorization interceptors process them. The patch also introduces an environment variable GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING to disable this check, which intentionally reverts the server to the vulnerable state if explicitly configured by the user.
Exploitation requires direct HTTP/2 communication with the vulnerable gRPC endpoint. Standard gRPC clients generally enforce the canonical path format, preventing accidental triggering of this vulnerability. An attacker must use specialized tools or custom scripts capable of manually assembling and transmitting raw HTTP/2 frames.
The attacker initiates an HTTP/2 connection and opens a new stream. During the HEADERS frame transmission, the attacker manually specifies the :path pseudo-header. Instead of providing the expected /{service}/{method} format, the attacker injects {service}/{method}, carefully omitting the initial forward slash.
The proof-of-concept code provided in the gRPC-Go test suite demonstrates this exact methodology. By writing the :path header as grpc.testing.TestService/UnaryCall and dispatching the raw HTTP/2 payload, the test confirms that the vulnerable server processes the request and returns a Status OK (0). After the patch is applied, the identical request correctly returns a Status Unimplemented (12) error.
In a production environment, this technique allows unauthenticated actors to access internal APIs, administrative gRPC endpoints, or restricted microservices exposed through Traefik. The exploit execution leaves standard access logs, but the path field will consistently lack the leading slash, providing a reliable detection artifact for incident response teams.
The vulnerability carries a CVSS v3.1 score of 9.3, reflecting a critical severity level. The attack vector is strictly network-based and requires no authentication, privileges, or user interaction. The primary consequence is a complete bypass of authorization policies enforced at the gateway or proxy level.
Successful exploitation directly compromises the confidentiality and integrity of the protected gRPC services. Attackers gain unauthorized access to data and operations intended only for authenticated users or internally routed traffic. The exact impact depends heavily on the functionality and permissions of the exposed gRPC service.
If the protected service handles database operations, the attacker obtains the ability to read, modify, or delete database records. If the service provides administrative functions, the attacker acquires control over the underlying application state or configuration parameters.
Availability is generally unaffected by the vulnerability itself, as it is an access control bypass rather than a resource exhaustion or memory corruption flaw. However, unauthorized access to administrative endpoints frequently leads to subsequent denial-of-service conditions if the attacker deliberately halts services or corrupts required data structures.
Organizations must upgrade all instances of Traefik and applications using gRPC-Go to the newly released patched versions. For Traefik v2 users, version 2.11.42 contains the fix. Traefik v3 users must upgrade to version 3.6.12 or the early access version 3.7.0-ea.3.
Developers utilizing gRPC-Go directly in custom binaries must upgrade the google.golang.org/grpc package to version 1.79.3. After updating the dependency in the go.mod file, the application must be recompiled and redeployed to effectively apply the security patch.
System administrators must ensure the environment variable GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING is omitted entirely or explicitly set to false. Setting this variable to true completely neutralizes the security patch and reinstates the vulnerability, leaving the system exposed to exploitation.
If immediate patching is structurally impossible, network defenders must deploy Web Application Firewall (WAF) or upstream proxy rules as a temporary mitigation. These rules must inspect raw HTTP/2 gRPC traffic and explicitly drop any request where the :path pseudo-header does not begin with a forward slash character.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Traefik v2 Traefik Labs | < 2.11.42 | 2.11.42 |
Traefik v3 Traefik Labs | < 3.6.12 | 3.6.12 |
Traefik v3 (EA) Traefik Labs | < 3.7.0-ea.3 | 3.7.0-ea.3 |
gRPC-Go Google | < 1.79.3 | 1.79.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-863 |
| Attack Vector | Network |
| CVSS Score | 9.3 |
| Impact | Authorization Bypass |
| Exploit Status | PoC Available |
| Authentication | Not Required |
The software performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check.