golang/go · error
tls: malformed encrypted_client_hello extension
Error message
tls: malformed encrypted_client_hello extension
What it means
Thrown by parseECHExt when the encrypted_client_hello extension in the outer ClientHello is structurally malformed. The extension must contain: a type byte (0 for outer, 1 for inner), and for outer type: KDF ID (uint16), AEAD ID (uint16), config ID (uint8), uint16-length-prefixed encapsulated key, and uint16-length-prefixed encrypted payload. For inner type, no additional data is allowed. Any truncated field, incorrect length prefix, or unexpected trailing data triggers this error. Note: processECHClientHello wraps this into errInvalidECHExt and sends a decode error alert before returning to the caller.
Source
Thrown at src/crypto/tls/ech.go:496
}
return true
}
// ECHRejectionError is the error type returned when ECH is rejected by a remote
// server. If the server offered a ECHConfigList to use for retries, the
// RetryConfigList field will contain this list.
//
// The client may treat an ECHRejectionError with an empty set of RetryConfigs
// as a secure signal from the server.
type ECHRejectionError struct {
RetryConfigList []byte
}
func (e *ECHRejectionError) Error() string {
return "tls: server rejected ECH"
}
var errMalformedECHExt = errors.New("tls: malformed encrypted_client_hello extension")
var errInvalidECHExt = errors.New("tls: client sent invalid encrypted_client_hello extension")
type echExtType uint8
const (
innerECHExt echExtType = 1
outerECHExt echExtType = 0
)
func parseECHExt(ext []byte) (echType echExtType, cs echCipher, configID uint8, encap []byte, payload []byte, err error) {
data := make([]byte, len(ext))
copy(data, ext)
s := cryptobyte.String(data)
var echInt uint8
if !s.ReadUint8(&echInt) {
err = errMalformedECHExt
return
}View on GitHub (pinned to b6b368adc5)
Solutions
- Ensure the client sends a properly formatted ECH extension following the RFC 9460 wire format: type(1) + KDF(2) + AEAD(2) + configID(1) + enc(2-length-prefixed) + payload(2-length-prefixed)
- Verify no TLS-intermediating device (proxy, WAF, load balancer) is modifying handshake packets
- Confirm client and server use compatible ECH specification versions (RFC 9460 final vs. older drafts)
- Use network packet capture (tcpdump/Wireshark) to verify the extension bytes on the wire
Defensive patterns
Strategy: validation
Try / catch
// parseECHExt errors are wrapped by processECHClientHello:
// - errMalformedECHExt → alertDecodeError → returns errInvalidECHExt
// - errInvalidECHExt → alertIllegalParameter → returns errInvalidECHExt
//
// if errors.Is(err, errInvalidECHExt) {
// // client sent malformed or invalid ECH extension
// } Prevention
- Ensure clients use RFC 9460-compliant ECH extension encoding
- Verify no middlebox modifies TLS handshake packets
- Monitor for decode error alerts as indicators of client compatibility issues
When it happens
Trigger: The outer ClientHello's encrypted_client_hello extension is too short to contain the required fields, has incorrect length prefixes for the encapsulated key or encrypted payload, the inner-type variant has unexpected trailing bytes, or the outer-type variant is missing the KDF ID, AEAD ID, config ID, enc, or payload fields.
Common situations: A non-compliant or buggy client sends a malformed ECH extension with truncated fields. A middlebox or TLS-terminating proxy corrupts the extension bytes. The client uses an incompatible ECH draft version with a different extension wire format than RFC 9460. A deliberate fuzzing or attack attempt sending garbage in the ECH extension.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- tls: invalid outer extensions
- tls: invalid reconstructed inner client hello
- tls: client sent invalid encrypted client hello extension
- tls: client sent encrypted_client_hello extension with unsup
- tls: client sent encrypted_client_hello extension but did no
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/64cf369657430401.
Report an issue: GitHub.