CVE-2026-81871 Overview
CVE-2026-81871 is a certificate validation flaw [CWE-295] in the OpenTelemetry-Go exporters/otlp/otlplog/otlploggrpc package. The exporter loads TLS environment variables such as OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE and OTEL_EXPORTER_OTLP_CERTIFICATE into cfg.tlsCfg, but newGRPCDialOptions never applies that configuration when building gRPC transport credentials. The exporter falls back to credentials.NewTLS with system roots and no client certificate, bypassing private CA pinning and mutual TLS. Applications relying solely on environment variables for TLS configuration send log telemetry over connections that trust any system-recognized certificate authority.
Critical Impact
A network attacker presenting a system-trusted certificate can intercept, read, or modify log telemetry destined for the OTLP collector.
Affected Products
- OpenTelemetry-Go exporters/otlp/otlplog/otlploggrpc prior to v0.21.0
- Go applications configuring OTLP log export via environment variables only
- Deployments relying on OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE for private CA pinning
Discovery Timeline
- 2026-09-16 - CVE-2026-81871 published to NVD
- 2026-09-16 - Last updated in NVD database
Technical Details for CVE-2026-81871
Vulnerability Analysis
The vulnerability resides in the gRPC dial option builder for the OTLP log exporter. The loadEnvTLS function correctly parses OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE, OTEL_EXPORTER_OTLP_CERTIFICATE, and the corresponding client certificate variables into cfg.tlsCfg. However, newGRPCDialOptions only checks cfg.gRPCCredentials, cfg.insecure, or a default branch. The default branch invokes credentials.NewTLS with a nil configuration, causing gRPC to fall back to the system root CA pool with no client certificate presented.
Any application configuring TLS solely through environment variables silently uses default TLS trust. Private CA pinning and mutual TLS enforcement are lost. This weakens the transport security guarantees expected between telemetry producers and the OpenTelemetry Collector.
Root Cause
The root cause is a missing dispatch case in the credential selection switch statement. The environment-loaded cfg.tlsCfg is populated but never wired into gRPC dial options. Only the programmatic WithTLSCredentials path applies the intended configuration.
Attack Vector
An attacker positioned on the network path between the application and the OTLP collector can present a certificate signed by any CA in the system trust store. The exporter accepts the connection, transmits log records containing potentially sensitive application data, and may accept altered responses. Mutual TLS enforcement is absent, so the collector cannot authenticate the client either.
if cfg.serviceConfig.Value != "" {
dialOpts = append(dialOpts, grpc.WithDefaultServiceConfig(cfg.serviceConfig.Value))
}
- // Prioritize GRPCCredentials over Insecure (passing both is an error).
+ // Prioritize configured credentials over Insecure (passing both is an error).
switch {
case cfg.gRPCCredentials.Value != nil:
dialOpts = append(dialOpts, grpc.WithTransportCredentials(cfg.gRPCCredentials.Value))
+ case cfg.tlsCfg.Value != nil:
+ dialOpts = append(dialOpts, grpc.WithTransportCredentials(credentials.NewTLS(cfg.tlsCfg.Value)))
case cfg.insecure.Value:
dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials()))
default:
Source: GitHub Commit c65d435b. The patch inserts a new switch case that applies cfg.tlsCfg via credentials.NewTLS when environment-derived TLS settings are present.
Detect Identity Attacks the Moment Authentication Fails
Singularity™ Identity surfaces credential misuse, lateral movement, and privilege escalation in real time, so you can contain the breach before it spreads.
Stop Identity AttacksDetection Methods for CVE-2026-81871
Indicators of Compromise
- Outbound OTLP gRPC connections from Go services succeeding despite a private CA misconfiguration on the collector
- Log telemetry received by unexpected endpoints or by collectors not pinned to the intended private CA
- Absence of client certificates in collector-side mutual TLS logs when environment variables specify one
Detection Strategies
- Inventory Go binaries importing go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc at versions below v0.21.0
- Compare application configuration: services setting OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE without calling WithTLSCredentials are exposed
- Perform TLS handshake inspection on OTLP collector endpoints to confirm the expected private CA is enforced
Monitoring Recommendations
- Alert on OTLP log traffic terminating on any TLS endpoint outside the sanctioned collector fleet
- Monitor collector logs for connections lacking expected client certificates
- Track dependency manifests (go.mod) in CI for vulnerable otlploggrpc versions
How to Mitigate CVE-2026-81871
Immediate Actions Required
- Upgrade go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc to v0.21.0 or later
- Audit all Go services exporting OTLP logs and confirm the effective TLS configuration matches intent
- Rotate any credentials or secrets that may have been transmitted through unauthenticated log telemetry
Patch Information
The fix is included in OpenTelemetry-Go otlploggrpc v0.21.0. Technical background is documented in GHSA-w34q-cm8f-9c5x. The patch adds a switch branch so cfg.tlsCfg is wrapped with credentials.NewTLS and passed to grpc.WithTransportCredentials.
Workarounds
- Explicitly construct TLS credentials in code with otlploggrpc.WithTLSCredentials instead of relying on environment variables
- Provide a credentials.TransportCredentials value through WithGRPCCredentials pinned to the private CA
- Enforce collector-side mutual TLS and reject connections without a valid client certificate
# Update the vulnerable module to the fixed release
go get go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc@v0.21.0
go mod tidy
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

