{"record":{"id":"67b4324982a5b7a9","repo":"XTLS/Xray-core","slug":"verify-token-mismatch","errorCode":null,"errorMessage":"verify token mismatch","messagePattern":"verify token mismatch","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"transport/internet/finalmask/xmc/server.go","lineNumber":203,"sourceCode":"\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"read encrypt response: %w\", err)\n\t\t}\n\n\t\tsharedSecret, err = rsa.DecryptPKCS1v15(rand.Reader, c.rsaPrivateKey, encryptedSharedSecret)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"decrypt shared secret: %w\", err)\n\t\t}\n\t\tif len(sharedSecret) != 16 {\n\t\t\treturn fmt.Errorf(\"bad shared secret length: %d\", len(sharedSecret))\n\t\t}\n\n\t\tdecryptedVerifyToken, err = rsa.DecryptPKCS1v15(rand.Reader, c.rsaPrivateKey, encryptedVerifyToken)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"decrypt verify token: %w\", err)\n\t\t}\n\n\t\tif len(decryptedVerifyToken) < 4 || !bytes.Equal(verifyToken, decryptedVerifyToken[:4]) {\n\t\t\treturn fmt.Errorf(\"verify token mismatch\")\n\t\t}\n\n\t\tc.reader, err = newCryptoReader(c.reader, sharedSecret)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"new crypto reader: %w\", err)\n\t\t}\n\n\t\tc.writer, err = newCryptoWriter(c.writer, sharedSecret)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"new crypto writer: %w\", err)\n\t\t}\n\n\t\t// verify password\n\t\treceivedPassword := decryptedVerifyToken[4:]\n\n\t\tif subtle.ConstantTimeCompare(receivedPassword, []byte(c.password)) != 1 {\n\t\t\twriteDisconnectPacket(c.writer, `{\"type\":\"translatable\",\"translate\":\"multiplayer.disconnect.authservers_down\"}`)\n\t\t\treturn fmt.Errorf(\"bad password\")","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/transport/internet/finalmask/xmc/server.go#L185-L221","documentation":"The decrypted verify token's first 4 bytes do not equal the random token the server generated for this handshake (or the token is shorter than 4 bytes). This is the anti-replay, session-binding check of the Minecraft encryption handshake: a legitimate client echoes the exact bytes back. A mismatch means the response belongs to a different session, was replayed, or the client is broken/hostile.","triggerScenarios":"Replaying a captured encryption-response packet from an earlier session; a client that echoes the wrong token bytes (endian/encoding bug); concurrency bug where two connections' tokens got crossed (e.g. shared state instead of per-connection verifyToken); decryptedVerifyToken shorter than 4 bytes.","commonSituations":"Attack tooling that records and replays handshakes; parallel connection tests where token state leaks between connections; client implementation that hashes or transforms the token instead of echoing it.","solutions":["Confirm verifyToken is generated and stored per connection (the code does rand.Read per handshake — verify no refactor made it shared).","If writing a client, echo the token bytes verbatim: encrypt exactly the 4 bytes received plus the password, nothing more.","Disconnect on mismatch — retrying with the same token would defeat the check's purpose.","Log the expected and received bytes at trace level during client development to pinpoint echo bugs."],"exampleFix":"// before\nif len(decryptedVerifyToken) < 4 || !bytes.Equal(verifyToken, decryptedVerifyToken[:4]) {\n    return fmt.Errorf(\"verify token mismatch\")\n}\n\n// after: distinguish the two failure shapes for clearer logs\nif len(decryptedVerifyToken) < 4 {\n    return fmt.Errorf(\"verify token too short: %d bytes\", len(decryptedVerifyToken))\n}\nif !bytes.Equal(verifyToken, decryptedVerifyToken[:4]) {\n    return fmt.Errorf(\"verify token mismatch\")\n}","handlingStrategy":"validation","validationCode":"if len(decryptedVerifyToken) < 4 {\n    return errors.New(\"verify token too short\")\n}\nif !bytes.Equal(verifyToken, decryptedVerifyToken[:4]) {\n    return errors.New(\"verify token mismatch\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Generate verifyToken fresh per connection with crypto/rand; never share it across sessions.","Client: echo the 4 token bytes verbatim before appending the password.","Treat mismatches as replay attempts and count them per IP for abuse detection."],"tags":["crypto","anti-replay","authentication","protocol-violation"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}