{"record":{"id":"aeac10e3f1a5b1ff","repo":"shadow1ng/fscan","slug":"invalid-saslstart-response","errorCode":null,"errorMessage":"invalid saslStart response","messagePattern":"invalid saslStart response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/services/mongodb.go","lineNumber":145,"sourceCode":"\t\tstate.IncrementTCPFailedPacketCount()\n\t\treturn &AuthResult{Success: false, ErrorType: ErrorTypeNetwork, Error: err}\n\t}\n\tresp, err = readMongoMsg(conn, timeout)\n\tif err != nil {\n\t\tstate.IncrementTCPFailedPacketCount()\n\t\treturn &AuthResult{Success: false, ErrorType: ErrorTypeNetwork, Error: err}\n\t}\n\n\tstartReply, err := parseMongoCommandReply(resp)\n\tif err != nil {\n\t\tstate.IncrementTCPFailedPacketCount()\n\t\treturn &AuthResult{Success: false, ErrorType: ErrorTypeNetwork, Error: err}\n\t}\n\tif !startReply.ok {\n\t\treturn &AuthResult{Success: false, ErrorType: ErrorTypeAuth, Error: fmt.Errorf(\"authentication failed: %s\", startReply.errmsg)}\n\t}\n\tif !startReply.conversationSet || len(startReply.payload) == 0 {\n\t\treturn &AuthResult{Success: false, ErrorType: ErrorTypeAuth, Error: fmt.Errorf(\"invalid saslStart response\")}\n\t}\n\n\tserverFirst := string(startReply.payload)\n\tclientFinal, err := buildMongoSCRAMClientFinal(cred.Username, cred.Password, clientFirstBare, serverFirst)\n\tif err != nil {\n\t\treturn &AuthResult{Success: false, ErrorType: ErrorTypeAuth, Error: err}\n\t}\n\n\tsaslContinueCmd := buildMongoCommand(\"admin\", orderedDoc(\n\t\tkv(\"saslContinue\", 1),\n\t\tkv(\"conversationId\", int(startReply.conversationID)),\n\t\tkv(\"payload\", []byte(clientFinal)),\n\t))\n\tif _, err := sendMongoMsg(ctx, conn, saslContinueCmd, timeout); err != nil {\n\t\tstate.IncrementTCPFailedPacketCount()\n\t\treturn &AuthResult{Success: false, ErrorType: ErrorTypeNetwork, Error: err}\n\t}\n\tresp, err = readMongoMsg(conn, timeout)","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/plugins/services/mongodb.go#L127-L163","documentation":"doMongoDBAuth performs a SCRAM-SHA-1 handshake against MongoDB. After sending saslStart, the server reply must set the conversation id and carry a non-empty payload containing the server-first message. If either is missing, the plugin rejects the reply as an 'invalid saslStart response' because the SCRAM challenge cannot proceed without it.","triggerScenarios":"The MongoDB server responds to the saslStart OpMsg command with ok=true but omits the 'conversationId' field or returns an empty 'payload' byte string — e.g. a proxy/middleware strips fields, or the server does not actually speak SCRAM.","commonSituations":"Scanning a mongod behind a load balancer or API gateway that mangles OP_MSG replies; targeting a non-MongoDB service on port 27017 that mimics minimal BSON responses; MongoDB versions/configurations with authentication mechanisms restricted so SCRAM negotiation behaves unexpectedly.","solutions":["Verify the target is a genuine MongoDB server by checking the hello/ismaster handshake response before attempting auth","Bypass or remove intermediate proxies/load balancers that alter OP_MSG payloads","Confirm the server supports SCRAM (authenticationMechanisms in getCmdLineOpts); if only MONGODB-CR/x509 is enabled use the appropriate plugin path","Re-run the scan directly against the host to rule out transient packet corruption"],"exampleFix":"// before\nif !startReply.conversationSet || len(startReply.payload) == 0 {\n    return &AuthResult{Success: false, ErrorType: ErrorTypeAuth, Error: fmt.Errorf(\"invalid saslStart response\")}\n}\n// after\nif !startReply.conversationSet || len(startReply.payload) == 0 {\n    return &AuthResult{Success: false, ErrorType: ErrorTypeAuth,\n        Error: fmt.Errorf(\"invalid saslStart response (conversationSet=%v payloadLen=%d)\", startReply.conversationSet, len(startReply.payload))}\n}","handlingStrategy":"try-catch","validationCode":"// Go: verify target speaks MongoDB before auth\nif err := probeHello(ctx, addr); err != nil {\n    return fmt.Errorf(\"not a MongoDB endpoint: %w\", err)\n}","typeGuard":"func validSaslStart(reply mongoReply) bool {\n    return reply.ok && reply.conversationSet && len(reply.payload) > 0\n}","tryCatchPattern":"res, err := doMongoDBAuth(ctx, addr, cred)\nif err != nil {\n    var authErr *AuthResult\n    if errors.As(err, &authErr) && authErr.ErrorType == ErrorTypeAuth {\n        log.Warn(\"saslStart reply malformed; target may not be SCRAM-capable\")\n        return\n    }\n    return err\n}","preventionTips":["Run a hello/ismaster fingerprint before attempting SCRAM auth","Scan direct connections without proxies on 27017","Confirm authenticationMechanisms include SCRAM-SHA-1 on the target"],"tags":["mongodb","auth","scram","protocol"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}