VYPR
High severityNVD Advisory· Published Jan 14, 2019· Updated Aug 5, 2024

CVE-2018-16886

CVE-2018-16886

Description

etcd versions 3.2.x before 3.2.26 and 3.3.x before 3.3.11 are vulnerable to an improper authentication issue when role-based access control (RBAC) is used and client-cert-auth is enabled. If an etcd client server TLS certificate contains a Common Name (CN) which matches a valid RBAC username, a remote attacker may authenticate as that user with any valid (trusted) client certificate in a REST API request to the gRPC-gateway.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

etcd 3.2.x before 3.2.26 and 3.3.x before 3.3.11 allow authentication bypass via CN matching in client certificates when RBAC and client-cert-auth are enabled.

Vulnerability

etcd versions 3.2.x before 3.2.26 and 3.3.x before 3.3.11 contain an improper authentication vulnerability in the gRPC-gateway when role-based access control (RBAC) is used and --client-cert-auth is enabled [1][2]. The AuthInfoFromTLS() function in auth/store.go incorrectly uses the Common Name (CN) from the etcd client server TLS certificate to authenticate REST API requests. If the CN matches a valid RBAC username, the request is authenticated as that user, bypassing proper certificate-based authentication [4].

Exploitation

An attacker must possess a valid TLS client certificate that is trusted by the etcd server (i.e., signed by a CA in the server's trust store). The attacker then crafts a REST API request to the gRPC-gateway endpoint, ensuring the client certificate's CN field matches the username of an existing RBAC user. No additional authentication credentials are required; the server will accept the request as if it came from that user [4]. The attack is network-based and does not require prior authentication or user interaction.

Impact

Successful exploitation allows the attacker to impersonate any RBAC user whose username matches the CN in the attacker's certificate. This can lead to unauthorized access to etcd data and operations, including reading or writing keys, modifying cluster configuration, or performing administrative actions, depending on the privileges assigned to the impersonated user. The confidentiality, integrity, and availability of the etcd cluster may be compromised [4].

Mitigation

The vulnerability is fixed in etcd versions 3.2.26 and 3.3.11, released on 2019-01-11 [1][2]. Users running affected versions should upgrade immediately. As a workaround, if upgrading is not possible, disable the gRPC-gateway or avoid using --client-cert-auth in conjunction with RBAC. The fix disables CommonName authentication for gRPC-gateway proxy requests [1][2]. No known exploitation in the wild has been reported as of the publication date.

AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
go.etcd.io/etcd/v3Go
>= 3.2.0, < 3.2.263.2.26
go.etcd.io/etcd/v3Go
>= 3.3.0, < 3.3.113.3.11
go.etcd.io/etcdGo
< 0.5.0-alpha.5.0.20190108173120-83c051b701d30.5.0-alpha.5.0.20190108173120-83c051b701d3

Affected products

10

Patches

2
bf9d0d8291dc

auth: disable CommonName auth for gRPC-gateway

https://github.com/etcd-io/etcdSam BatscheletJan 2, 2019via ghsa
1 file changed · +21 0
  • auth/store.go+21 0 modified
    @@ -1166,6 +1166,27 @@ func (as *authStore) AuthInfoFromTLS(ctx context.Context) (ai *AuthInfo) {
     			Username: chains[0].Subject.CommonName,
     			Revision: as.Revision(),
     		}
    +		md, ok := metadata.FromIncomingContext(ctx)
    +		if !ok {
    +			return nil
    +		}
    +
    +		// gRPC-gateway proxy request to etcd server includes Grpcgateway-Accept
    +		// header. The proxy uses etcd client server certificate. If the certificate
    +		// has a CommonName we should never use this for authentication.
    +		if gw := md["grpcgateway-accept"]; len(gw) > 0 {
    +			if as.lg != nil {
    +				as.lg.Warn(
    +					"ignoring common name in gRPC-gateway proxy request",
    +					zap.String("common-name", ai.Username),
    +					zap.String("user-name", ai.Username),
    +					zap.Uint64("revision", ai.Revision),
    +				)
    +			} else {
    +				plog.Warningf("ignoring common name in gRPC-gateway proxy request %s", ai.Username)
    +			}
    +			return nil
    +		}
     		if as.lg != nil {
     			as.lg.Debug(
     				"found command name",
    
019150963754

auth, etcdserver: authenticate clients based on certificate CommonName

https://github.com/etcd-io/etcdHitoshi MitakeNov 21, 2016via ghsa
4 files changed · +43 4
  • auth/store.go+27 0 modified
    @@ -30,7 +30,9 @@ import (
     	"github.com/coreos/pkg/capnslog"
     	"golang.org/x/crypto/bcrypt"
     	"golang.org/x/net/context"
    +	"google.golang.org/grpc/credentials"
     	"google.golang.org/grpc/metadata"
    +	"google.golang.org/grpc/peer"
     )
     
     var (
    @@ -159,6 +161,9 @@ type AuthStore interface {
     
     	// AuthInfoFromCtx gets AuthInfo from gRPC's context
     	AuthInfoFromCtx(ctx context.Context) (*AuthInfo, error)
    +
    +	// AuthInfoFromTLS gets AuthInfo from TLS info of gRPC's context
    +	AuthInfoFromTLS(ctx context.Context) *AuthInfo
     }
     
     type authStore struct {
    @@ -950,6 +955,28 @@ func (as *authStore) isValidSimpleToken(token string, ctx context.Context) bool
     	return false
     }
     
    +func (as *authStore) AuthInfoFromTLS(ctx context.Context) *AuthInfo {
    +	peer, ok := peer.FromContext(ctx)
    +	if !ok || peer == nil || peer.AuthInfo == nil {
    +		return nil
    +	}
    +
    +	tlsInfo := peer.AuthInfo.(credentials.TLSInfo)
    +	for _, chains := range tlsInfo.State.VerifiedChains {
    +		for _, chain := range chains {
    +			cn := chain.Subject.CommonName
    +			plog.Debugf("found common name %s", cn)
    +
    +			return &AuthInfo{
    +				Username: cn,
    +				Revision: as.Revision(),
    +			}
    +		}
    +	}
    +
    +	return nil
    +}
    +
     func (as *authStore) AuthInfoFromCtx(ctx context.Context) (*AuthInfo, error) {
     	md, ok := metadata.FromContext(ctx)
     	if !ok {
    
  • etcdserver/api/v3rpc/maintenance.go+2 1 modified
    @@ -47,6 +47,7 @@ type RaftStatusGetter interface {
     }
     
     type AuthGetter interface {
    +	AuthInfoFromCtx(ctx context.Context) (*auth.AuthInfo, error)
     	AuthStore() auth.AuthStore
     }
     
    @@ -152,7 +153,7 @@ type authMaintenanceServer struct {
     }
     
     func (ams *authMaintenanceServer) isAuthenticated(ctx context.Context) error {
    -	authInfo, err := ams.ag.AuthStore().AuthInfoFromCtx(ctx)
    +	authInfo, err := ams.ag.AuthInfoFromCtx(ctx)
     	if err != nil {
     		return err
     	}
    
  • etcdserver/server.go+1 1 modified
    @@ -1022,7 +1022,7 @@ func (s *EtcdServer) checkMembershipOperationPermission(ctx context.Context) err
     	// in the state machine layer
     	// However, both of membership change and role management requires the root privilege.
     	// So careful operation by admins can prevent the problem.
    -	authInfo, err := s.AuthStore().AuthInfoFromCtx(ctx)
    +	authInfo, err := s.AuthInfoFromCtx(ctx)
     	if err != nil {
     		return err
     	}
    
  • etcdserver/v3_server.go+13 2 modified
    @@ -617,7 +617,7 @@ func (s *EtcdServer) RoleDelete(ctx context.Context, r *pb.AuthRoleDeleteRequest
     // doSerialize handles the auth logic, with permissions checked by "chk", for a serialized request "get". Returns a non-nil error on authentication failure.
     func (s *EtcdServer) doSerialize(ctx context.Context, chk func(*auth.AuthInfo) error, get func()) error {
     	for {
    -		ai, err := s.AuthStore().AuthInfoFromCtx(ctx)
    +		ai, err := s.AuthInfoFromCtx(ctx)
     		if err != nil {
     			return err
     		}
    @@ -652,7 +652,7 @@ func (s *EtcdServer) processInternalRaftRequestOnce(ctx context.Context, r pb.In
     		ID: s.reqIDGen.Next(),
     	}
     
    -	authInfo, err := s.AuthStore().AuthInfoFromCtx(ctx)
    +	authInfo, err := s.AuthInfoFromCtx(ctx)
     	if err != nil {
     		return nil, err
     	}
    @@ -802,3 +802,14 @@ func (s *EtcdServer) linearizableReadNotify(ctx context.Context) error {
     		return ErrStopped
     	}
     }
    +
    +func (s *EtcdServer) AuthInfoFromCtx(ctx context.Context) (*auth.AuthInfo, error) {
    +	if s.Cfg.ClientCertAuthEnabled {
    +		authInfo := s.AuthStore().AuthInfoFromTLS(ctx)
    +		if authInfo != nil {
    +			return authInfo, nil
    +		}
    +	}
    +
    +	return s.AuthStore().AuthInfoFromCtx(ctx)
    +}
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

16

News mentions

0

No linked articles in our index yet.