{"record":{"id":"70713ef9686ca310","repo":"golang/go","slug":"tls-server-sent-a-cookie-in-a-normal-serverhello","errorCode":null,"errorMessage":"tls: server sent a cookie in a normal ServerHello","messagePattern":"tls: server sent a cookie in a normal ServerHello","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/tls/handshake_client_tls13.go","lineNumber":422,"sourceCode":"\tif err := hs.checkServerHelloOrHRR(); err != nil {\n\t\treturn err\n\t}\n\n\tc.didHRR = true\n\treturn nil\n}\n\nfunc (hs *clientHandshakeStateTLS13) processServerHello() error {\n\tc := hs.c\n\n\tif bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {\n\t\tc.sendAlert(alertUnexpectedMessage)\n\t\treturn errors.New(\"tls: server sent two HelloRetryRequest messages\")\n\t}\n\n\tif len(hs.serverHello.cookie) != 0 {\n\t\tc.sendAlert(alertUnsupportedExtension)\n\t\treturn errors.New(\"tls: server sent a cookie in a normal ServerHello\")\n\t}\n\n\tif hs.serverHello.selectedGroup != 0 {\n\t\tc.sendAlert(alertDecodeError)\n\t\treturn errors.New(\"tls: malformed key_share extension\")\n\t}\n\n\tif hs.serverHello.serverShare.group == 0 {\n\t\tc.sendAlert(alertIllegalParameter)\n\t\treturn errors.New(\"tls: server did not send a key share\")\n\t}\n\tif !slices.ContainsFunc(hs.hello.keyShares, func(ks keyShare) bool {\n\t\treturn ks.group == hs.serverHello.serverShare.group\n\t}) {\n\t\tc.sendAlert(alertIllegalParameter)\n\t\treturn errors.New(\"tls: server selected unsupported group\")\n\t}\n","sourceCodeStart":404,"sourceCodeEnd":440,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/tls/handshake_client_tls13.go#L404-L440","documentation":"In a genuine ServerHello (not an HRR), RFC 8446 §4.2.2 forbids the cookie extension; cookies belong only in HelloRetryRequest. Go detects a non-empty hs.serverHello.cookie and sends an `unsupported_extension` alert. Indicates a server that is misusing the cookie extension.","triggerScenarios":"ServerHello (random != helloRetryRequestRandom) carries a non-empty cookie field. Reached in processServerHello during a normal TLS 1.3 handshake.","commonSituations":"Server implementation that always echoes the cookie, fuzz-generated ServerHello, or a malicious peer probing the client. Normal OpenSSL/BoringSSL/Go servers never do this.","solutions":["Report to the server operator — the cookie extension is HRR-only.","Capture the handshake with Wireshark to confirm the offending extension is coming from the server, not a proxy.","Eliminate any TLS-terminating proxy/load-balancer in the path that may be injecting extensions.","If self-operated, fix the server's ServerHello encoder to omit cookie outside HRR."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"conn, err := tls.Dial(\"tcp\", addr, cfg)\nif err != nil && strings.Contains(err.Error(), \"cookie in a normal ServerHello\") {\n    // cookie is HRR-only; the server or a proxy is misbehaving\n    log.Printf(\"peer %s injected a cookie outside HRR\", addr)\n    return err\n}","preventionTips":["Audit TLS-terminating proxies for extensions they inject.","Prefer direct connections during diagnosis to isolate the source of unexpected extensions.","Test new server releases against the Go client before deployment."],"tags":["tls","tls13","handshake","cookie","protocol-violation","network","go"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}