golang/go · error

tls: invalid outer extensions

Error message

tls: invalid outer extensions

What it means

Thrown during ECH inner ClientHello reconstruction when the outer_extensions compressed reference list includes the encrypted_client_hello extension type. RFC 9460 explicitly forbids this because the inner ClientHello carries its own ECH indicator (a single byte set to innerECHExt=1), and referencing the outer ECH extension would create ambiguity and potential security issues.

Source

Thrown at src/crypto/tls/ech.go:337

				if !extensions.ReadUint16(&extension) ||
					!extensions.ReadUint16LengthPrefixed(&extData) {
					recon.SetError(errors.New("tls: invalid inner client hello"))
					return
				}
				if extension == extensionECHOuterExtensions {
					if !extData.ReadUint8LengthPrefixed(&extData) {
						recon.SetError(errors.New("tls: invalid inner client hello"))
						return
					}
					var i int
					for !extData.Empty() {
						var extType uint16
						if !extData.ReadUint16(&extType) {
							recon.SetError(errors.New("tls: invalid inner client hello"))
							return
						}
						if extType == extensionEncryptedClientHello {
							recon.SetError(errors.New("tls: invalid outer extensions"))
							return
						}
						for ; i <= len(rawOuterExts); i++ {
							if i == len(rawOuterExts) {
								recon.SetError(errors.New("tls: invalid outer extensions"))
								return
							}
							if rawOuterExts[i].extType == extType {
								break
							}
						}
						recon.AddUint16(rawOuterExts[i].extType)
						recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) {
							recon.AddBytes(rawOuterExts[i].data)
						})
					}
				} else {
					recon.AddUint16(extension)

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Ensure the ECH client implementation excludes encrypted_client_hello from the outer_extensions compressed list — this is explicitly forbidden by RFC 9460
  2. Update the client ECH library to the latest version that handles the inner/outer extension separation correctly
  3. If using a custom ECH implementation, verify that the extension compression logic filters out the ECH extension type
  4. Report as a bug to the client library vendor if using a third-party ECH implementation
Defensive patterns

Strategy: validation

Try / catch

// Wrapped into errInvalidECHExt by processECHClientHello.

Prevention

When it happens

Trigger: The inner ClientHello's outer_extensions list contains the extensionEncryptedClientHello type ID, which is prohibited by the ECH specification.

Common situations: A non-compliant ECH client implementation that incorrectly includes the ECH extension in the compressed outer extensions reference. A deliberate protocol violation attempt. A client using an incompatible ECH draft version with different rules.

Understand the failure class

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/5f6f2e086c273551. Report an issue: GitHub.