From 6e4e6fdab32c4a993263cea2cfbcbdb48f9fc17c Mon Sep 17 00:00:00 2001
From: rcmadhankumar <madhankumar.chellamuthu@suse.com>
Date: Wed, 25 Mar 2026 14:45:45 +0530
Subject: [PATCH] CVE-2026-33186: containerd: google.golang.org/grpc:
 authorization bypass due to improper validation of the HTTP/2 :path
 pseudo-header

It is an Authorization Bypass (CWE-285) resulting from Improper
Input Validation (CWE-20) of the HTTP/2 :path pseudo-header.

The gRPC-Go server was too lenient in its routing logic,
accepting requests where the :path omitted the mandatory leading
slash (e.g., Service/Method instead of /Service/Method). While
the server successfully routed these requests to the correct handler,
authorization interceptors (including the official grpc/authz package)
evaluated the raw, non-canonical path string. Consequently, "deny"
rules defined using canonical paths (starting with /) failed to match
the incoming request, allowing it to bypass the policy if a fallback
"allow" rule was present.

This affects gRPC-Go servers that meet both of the following criteria:

- They use path-based authorization interceptors, such as the official
 RBAC implementation in google.golang.org/grpc/authz or custom
interceptors relying on info.FullMethod or grpc.Method(ctx).
- Their security policy contains specific "deny" rules for canonical
paths but allows other requests by default (a fallback "allow" rule).

The vulnerability is exploitable by an attacker who can send raw
HTTP/2 frames with malformed :path headers directly to the gRPC server.

Fix:
-  Added "outermost" interceptors that validates the path before any
other authorization logic runs(pathValidationInterceptor and
pathValidationStreamInterceptor)

reference: https://github.com/grpc/grpc-go/security/advisories/GHSA-p77j-4mvh-x3m3

Bugs: bsc#1260296
Fixes: CVE-2026-33186
Signed-off-by: rcmadhankumar <madhankumar.chellamuthu@suse.com>
---
 services/server/server.go | 34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/services/server/server.go b/services/server/server.go
index 5b772ac94..0ab92b118 100644
--- a/services/server/server.go
+++ b/services/server/server.go
@@ -64,6 +64,8 @@ import (
 	"github.com/containerd/containerd/sys"
 	"github.com/containerd/log"
 	"github.com/containerd/platforms"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
 )
 
 // CreateTopLevelDirectories creates the top-level root and state directories.
@@ -204,9 +206,37 @@ func New(ctx context.Context, config *srvconfig.Config) (*Server, error) {
 		RegisterTTRPC(*ttrpc.Server) error
 	}
 
+	// pathValidationInterceptor handles Unary RPCs (simple Request/Response)
+	pathValidationInterceptor := func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
+		// If the path is empty or doesn't start with '/', it's a bypass attempt.
+		if info.FullMethod == "" || info.FullMethod[0] != '/' {
+			return nil, status.Errorf(codes.Unimplemented, "malformed method name")
+		}
+		return handler(ctx, req)
+	}
+
+	// pathValidationStreamInterceptor handles Streaming RPCs (Logs, Events, etc.)
+	pathValidationStreamInterceptor := func(srv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
+		// Same logic as Unary, but using StreamServerInfo
+		if info.FullMethod == "" || info.FullMethod[0] != '/' {
+			return status.Errorf(codes.Unimplemented, "malformed method name")
+		}
+		return handler(srv, ss)
+	}
+
+	// 1. Prepare the security shield options
+	securityShield := []grpc.ServerOption{
+		grpc.ChainUnaryInterceptor(pathValidationInterceptor),
+		grpc.ChainStreamInterceptor(pathValidationStreamInterceptor),
+	}
+
 	var (
-		grpcServer = grpc.NewServer(serverOpts...)
-		tcpServer  = grpc.NewServer(tcpServerOpts...)
+		// 2. Initialize the gRPC Server
+		// We append the shield to your existing options and use '...' to unpack them
+		grpcServer = grpc.NewServer(append(serverOpts, securityShield...)...)
+
+		// 3. Initialize the TCP Server
+		tcpServer = grpc.NewServer(append(tcpServerOpts, securityShield...)...)
 
 		grpcServices  []grpcService
 		tcpServices   []tcpService
-- 
2.53.0

