All advisories
Draft

ACCEPT_UNTRUSTED Skips SAN Validation Entirely

envoyproxy/envoy

Affected packages

envoy other
Affected versions= c33d01624d5b173b5d6e5c0c0474d480cab69b7b
Patched versionsNot specified

Description

ACCEPT_UNTRUSTED Skips SAN Validation Entirely

Affected commit: c33d01624d
Sink: source/common/tls/cert_validator/default_validator.cc:303

Summary

With trust_chain_verification: ACCEPT_UNTRUSTED, verifyCertAndUpdateStatus short-circuits to return true via return (allow_untrusted_certificate_ || success), regardless of whether verifyCertificate rejected the client certificate's SAN. Any certificate from any issuer passes mTLS authentication when this option is set.

Detail

// source/common/tls/cert_validator/default_validator.cc:303
return (allow_untrusted_certificate_ || success);

When allow_untrusted_certificate_ is true (set by ACCEPT_UNTRUSTED), the short-circuit || ignores success. If verifyCertificate() returns Failed because the SAN doesn't match the configured matcher, success is false, but the function still returns true.

Reproduce

#!/bin/bash
set -e

# Clone and identify HEAD
git clone --depth 1 https://github.com/envoyproxy/envoy.git /tmp/envoy-repro
cd /tmp/envoy-repro
echo "HEAD: $(git rev-parse HEAD)"

# Verify the vulnerable short-circuit OR is still present
echo "--- Vulnerable code path ---"
grep -n 'allow_untrusted_certificate_ || success' \
  source/common/tls/cert_validator/default_validator.cc

# Show full context: verifyCertAndUpdateStatus return
sed -n '295,303p' source/common/tls/cert_validator/default_validator.cc

The vulnerable code at default_validator.cc:303:

return (allow_untrusted_certificate_ || success);

When trust_chain_verification: ACCEPT_UNTRUSTED is configured, allow_untrusted_certificate_ is true. The C++ short-circuit || returns true immediately without evaluating success. If verifyCertificate() returned ClientValidationStatus::Failed because the client certificate's SAN does not match any configured matcher, success is false — but the function returns true anyway.

An attacker with any CA-signed certificate (even self-signed when chain verification is skipped) connects to an mTLS listener with this setting. The handshake succeeds regardless of SAN mismatch. The attacker is authenticated as a valid mTLS peer, bypassing all SAN-based RBAC controls downstream.

Expected output:

HEAD: <resolved-commit>
--- Vulnerable code path ---
303:  return (allow_untrusted_certificate_ || success);

Credit

Zheng Yu @ Depthfirst