{"record":{"id":"675f42d49c5a0d1d","repo":"grpc/grpc-go","slug":"requires-securitylevel-v-connection-has-v","errorCode":null,"errorMessage":"requires SecurityLevel %v; connection has %v","messagePattern":"requires SecurityLevel (.+?); connection has (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/credentials.go","lineNumber":303,"sourceCode":"// CheckSecurityLevel checks if a connection's security level is greater than or equal to the specified one.\n// It returns success if 1) the condition is satisfied or 2) AuthInfo struct does not implement GetCommonAuthInfo() method\n// or 3) CommonAuthInfo.SecurityLevel has an invalid zero value. For 2) and 3), it is for the purpose of backward-compatibility.\n//\n// This API is experimental.\nfunc CheckSecurityLevel(ai AuthInfo, level SecurityLevel) error {\n\ttype internalInfo interface {\n\t\tGetCommonAuthInfo() CommonAuthInfo\n\t}\n\tif ai == nil {\n\t\treturn errors.New(\"AuthInfo is nil\")\n\t}\n\tif ci, ok := ai.(internalInfo); ok {\n\t\t// CommonAuthInfo.SecurityLevel has an invalid value.\n\t\tif ci.GetCommonAuthInfo().SecurityLevel == InvalidSecurityLevel {\n\t\t\treturn nil\n\t\t}\n\t\tif ci.GetCommonAuthInfo().SecurityLevel < level {\n\t\t\treturn fmt.Errorf(\"requires SecurityLevel %v; connection has %v\", level, ci.GetCommonAuthInfo().SecurityLevel)\n\t\t}\n\t}\n\t// The condition is satisfied or AuthInfo struct does not implement GetCommonAuthInfo() method.\n\treturn nil\n}\n\n// ChannelzSecurityInfo defines the interface that security protocols should implement\n// in order to provide security info to channelz.\n//\n// This API is experimental.\ntype ChannelzSecurityInfo interface {\n\tGetSecurityValue() ChannelzSecurityValue\n}\n\n// ChannelzSecurityValue defines the interface that GetSecurityValue() return value\n// should satisfy. This interface should only be satisfied by *TLSChannelzSecurityValue\n// and *OtherChannelzSecurityValue.\n//","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/credentials/credentials.go#L285-L321","documentation":"Returned by credentials.CheckSecurityLevel when the established connection's CommonAuthInfo.SecurityLevel is lower than the level the caller required. SecurityLevel ordering is NoSecurity(1) < IntegrityOnly(2) < PrivacyAndIntegrity(3). Per-RPC credential implementations call CheckSecurityLevel to refuse sending secrets over an inadequately protected transport.","triggerScenarios":"A PerRPCCredentials implementation (e.g. the GCP service-account-identity credentials at gcp_service_account_identity_credentials.go:129) calls CheckSecurityLevel(ai, PrivacyAndIntegrity) and the connection's AuthInfo reports a lower level. Also surfaces anywhere a user manually calls CheckSecurityLevel with a level above what the current transport provides.","commonSituations":"Using per-RPC token/OAuth credentials over an insecure channel (grpc.WithInsecure / insecure.NewCredentials) instead of TLS or ALTS; using IntegrityOnly credentials (e.g. certain ALTS configs) when the caller requires PrivacyAndIntegrity; a custom TransportCredentials that fails to set SecurityLevel correctly (leaving it at a low value).","solutions":["Use a transport credential that provides the required level: TLS (credentials.NewTLS) or ALTS (alts.NewClientCreds/NewServerCreds) which both provide PrivacyAndIntegrity.","Do not pair token/per-RPC credentials with insecure.NewCredentials(); RequireTransportSecurity()==true exists precisely to prevent this.","If implementing custom TransportCredentials, set CommonAuthInfo.SecurityLevel accurately in your AuthInfo struct.","Lower the required level only if you have verified the data sensitivity allows it."],"exampleFix":"// before: token creds over insecure transport -> CheckSecurityLevel fails\nimport \"google.golang.org/grpc/credentials/insecure\"\ncreds, _ := google.NewServiceAccountIdentityCredentials(ctx, aud)\nconn, _ := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithPerRPCCredentials(creds))\n\n// after: use TLS so the connection reports PrivacyAndIntegrity\ntlsCreds := credentials.NewTLS(&tls.Config{})\nconn, _ := grpc.Dial(addr, grpc.WithTransportCredentials(tlsCreds), grpc.WithPerRPCCredentials(creds))","handlingStrategy":"validation","validationCode":"// Ensure the transport provides PrivacyAndIntegrity before attaching token creds.\nfunc ensureSecureTransport(creds credentials.TransportCredentials) error {\n    // ALTS and TLS both report PrivacyAndIntegrity; insecure does not.\n    // There is no public field to inspect; enforce by policy:\n    if _, ok := creds.(*credentials.TlsCapableCreds); ok { return nil }\n    // For ALTS, trust by type/name:\n    return nil // best practice: never pair per-RPC creds with insecure.NewCredentials()\n}\n\n// Stronger runtime check: call CheckSecurityLevel with the connection's AuthInfo\n// before sending secrets:\n// err := credentials.CheckSecurityLevel(peer.AuthInfo, credentials.PrivacyAndIntegrity)","typeGuard":"func isTransportSecure(info credentials.ProtocolInfo) bool {\n    // ALTS reports SecurityProtocol=\"alts\"; TLS reports \"tls\".\n    return info.SecurityProtocol == \"tls\" || info.SecurityProtocol == \"alts\"\n}","tryCatchPattern":"// In GetRequestMetadata-style code, return a clear error instead of leaking tokens.\nif err := credentials.CheckSecurityLevel(ai, credentials.PrivacyAndIntegrity); err != nil {\n    return nil, fmt.Errorf(\"refusing to send credentials over insecure transport: %w\", err)\n}","preventionTips":["Never combine per-RPC credentials with insecure.NewCredentials().","Always use TLS or ALTS transport credentials when RequireTransportSecurity()==true.","In custom TransportCredentials, set CommonAuthInfo.SecurityLevel correctly.","Call credentials.CheckSecurityLevel in your PerRPCCredentials.GetRequestMetadata."],"tags":["grpc","credentials","security","tls","transport-security","validation"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}