{"record":{"id":"1358cf4560812bc3","repo":"shadow1ng/fscan","slug":"sasl-handshake-error-d","errorCode":null,"errorMessage":"SASL handshake error: %d","messagePattern":"SASL handshake error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/services/kafka.go","lineNumber":113,"sourceCode":"\n\t// Step 2: SASL/PLAIN 认证 (如果需要)\n\tif cred.Username != \"\" || cred.Password != \"\" {\n\t\t// SaslHandshake: mechanism=PLAIN (api_key=17, api_version=0)\n\t\tbody := kafkaString(\"PLAIN\")\n\t\tif err := kafkaSend(conn, 17, 0, body); err != nil {\n\t\t\tstate.IncrementTCPFailedPacketCount()\n\t\t\treturn &AuthResult{Success: false, ErrorType: ErrorTypeNetwork, Error: err}\n\t\t}\n\t\tresp, err := kafkaRecv(conn)\n\t\tif err != nil {\n\t\t\tstate.IncrementTCPFailedPacketCount()\n\t\t\treturn &AuthResult{Success: false, ErrorType: classifyKafkaErrorType(err), Error: err}\n\t\t}\n\t\t// SaslHandshake 响应: [4B error_code] + [mechanisms array]\n\t\tif len(resp) >= 2 {\n\t\t\tcode := int16(binary.BigEndian.Uint16(resp[:2]))\n\t\t\tif code != 0 {\n\t\t\t\treturn &AuthResult{Success: false, ErrorType: ErrorTypeAuth, Error: fmt.Errorf(\"SASL handshake error: %d\", code)}\n\t\t\t}\n\t\t}\n\n\t\t// SaslAuthenticate: PLAIN token = \\x00user\\x00pass (api_key=36, api_version=0)\n\t\ttoken := []byte(\"\\x00\" + cred.Username + \"\\x00\" + cred.Password)\n\t\tauthBody := kafkaBytes(token)\n\t\tif err := kafkaSend(conn, 36, 0, authBody); err != nil {\n\t\t\tstate.IncrementTCPFailedPacketCount()\n\t\t\treturn &AuthResult{Success: false, ErrorType: ErrorTypeNetwork, Error: err}\n\t\t}\n\t\tresp, err = kafkaRecv(conn)\n\t\tif err != nil {\n\t\t\tstate.IncrementTCPFailedPacketCount()\n\t\t\treturn &AuthResult{Success: false, ErrorType: classifyKafkaErrorType(err), Error: err}\n\t\t}\n\t\tif len(resp) >= 2 {\n\t\t\tcode := int16(binary.BigEndian.Uint16(resp[:2]))\n\t\t\tif code != 0 {","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/plugins/services/kafka.go#L95-L131","documentation":"doKafkaAuth parses the SaslHandshake response and reads the first 2 bytes as a big-endian int16 error_code. A non-zero code means the broker rejected the handshake (unknown mechanism, unsupported SASL version, auth disabled, security protocol mismatch). The numeric Kafka protocol error code is embedded in the message for diagnosis.","triggerScenarios":"doKafkaAuth: after sending the SaslHandshake request (api_key=17) over PLAIN, kafkaRecv returns a response whose first 2 bytes are a non-zero error code.","commonSituations":"Broker listener configured with SASL_SSL while plugin connects plaintext (or vice versa); broker does not support the PLAIN mechanism (only SCRAM); SASL not enabled on the listener at all; api_version mismatch with older brokers.","solutions":["Match the security protocol: use TLS for SASL_SSL listeners before attempting SASL","Verify the broker listener supports the PLAIN mechanism (check sasl.enabled.mechanisms)","Decode the specific code (e.g. 33=UnsupportedSaslMechanism, 34=IllegalSaslState) to target the fix","Confirm the broker's listener port is the SASL-enabled one, not PLAINTEXT"],"exampleFix":"// before\nif code != 0 {\n    return &AuthResult{Success: false, ErrorType: ErrorTypeAuth, Error: fmt.Errorf(\"SASL handshake error: %d\", code)}\n}\n// after\nif code != 0 {\n    return &AuthResult{Success: false, ErrorType: ErrorTypeAuth, Error: fmt.Errorf(\"SASL handshake error: %d (%s)\", code, kafkaSaslHandshakeErrText(code))}\n}","handlingStrategy":"try-catch","validationCode":"// Probe the listener's security protocol before SASL\n// e.g. send ApiVersions unencrypted; if the broker requires TLS the frame fails early","typeGuard":"func isHandshakeRejected(code int16) bool {\n    return code != 0 // 33 UnsupportedSaslMechanism, 34 IllegalSaslState\n}","tryCatchPattern":"res := plugin.Scan(info, config, state)\nif a := res.AuthResults; a != nil {\n    for _, r := range a {\n        if r.Error != nil && strings.Contains(r.Error.Error(), \"SASL handshake error\") {\n            log.Printf(\"kafka: broker rejected handshake (%v); check listener protocol/mechanism\", r.Error)\n        }\n    }\n}","preventionTips":["Match plaintext vs SASL_SSL to the broker listener before authenticating","Confirm PLAIN is in sasl.enabled.mechanisms (else use SCRAM)","Decode Kafka protocol error codes (33/34) for targeted fixes","Pin api_version supported by the broker version in use"],"tags":["kafka","sasl","authentication","protocol"],"backgroundTag":"authentication-required","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}