XTLS/Xray-core · error
bad password
Error message
bad password
What it means
Password authentication failed. This fork smuggles the password after the 4-byte verify token inside the encrypted verify-token field; after handshake success the server constant-time-compares decryptedVerifyToken[4:] against the configured c.password. On mismatch it writes a disconnect packet (mimicking Mojang's authservers_down message) and aborts the login.
Source
Thrown at transport/internet/finalmask/xmc/server.go:221
return fmt.Errorf("verify token mismatch")
}
c.reader, err = newCryptoReader(c.reader, sharedSecret)
if err != nil {
return fmt.Errorf("new crypto reader: %w", err)
}
c.writer, err = newCryptoWriter(c.writer, sharedSecret)
if err != nil {
return fmt.Errorf("new crypto writer: %w", err)
}
// verify password
receivedPassword := decryptedVerifyToken[4:]
if subtle.ConstantTimeCompare(receivedPassword, []byte(c.password)) != 1 {
writeDisconnectPacket(c.writer, `{"type":"translatable","translate":"multiplayer.disconnect.authservers_down"}`)
return fmt.Errorf("bad password")
}
if !found {
if err = writeDisconnectPacket(c.writer, `{"text":"You are not white-listed on this server!"}`); err != nil {
return fmt.Errorf("write unknown login profile disconnect: %w", err)
}
return fmt.Errorf("unknown login profile")
}
loginName := String(profile.Username)
propertyCount := Varint(1)
propertyName := String("textures")
texturesValue := String(profile.TexturesValue)
signed := Boolean(true)
texturesSignature := String(profile.TexturesSignature)
if err = writePacket(c.writer, 0x02, &profile.UUID, &loginName, &propertyCount, &propertyName, &texturesValue, &signed, &texturesSignature); err != nil {
return fmt.Errorf("write login finished: %w", err)
}
View on GitHub (pinned to 7d214f8b09)
Solutions
- Set the identical password byte-for-byte in both the server config and the client's verify-token payload; watch for trailing whitespace/newlines.
- If you maintain the client, verify it sends verifyToken[0:4] || password exactly, with no length prefix or padding.
- Compare lengths first in a log line (never log the password itself) — a 0-length received password means the client sends no suffix at all.
- After changing the password, restart both ends; there is no re-negotiation path mid-handshake.
Example fix
// client side, before: send only the echo token
token := verifyToken // 4 bytes
// after: append the password this server expects
token := append(append([]byte{}, verifyToken...), []byte(password)...)
encrypted, err := rsa.EncryptPKCS1v15(rand.Reader, serverPub, token) Defensive patterns
Strategy: validation
Validate before calling
// server startup: fail fast on empty/whitespace passwords
if strings.TrimSpace(c.password) == "" && requirePassword {
return errors.New("xmc password must be configured")
} Try / catch
if subtle.ConstantTimeCompare(receivedPassword, []byte(c.password)) != 1 {
writeDisconnectPacket(c.writer, `{"type":"translatable","translate":"multiplayer.disconnect.authservers_down"}`)
return errors.New("bad password") // already the pattern; keep the disconnect before returning
} Prevention
- Distribute the password to clients via the same mechanism/channel as the config to avoid drift after rotation.
- Client: build the payload as verifyToken[0:4] || password with no separators or length prefixes.
- Log lengths (not contents) of expected vs received passwords to debug encoding mismatches.
When it happens
Trigger: Client concatenated the wrong password (or none) after the 4 echo bytes: wrong password configured, password empty on one side but not the other, trailing whitespace/newline in either config, or a client that only sends the bare 4-byte token so the suffix comparison fails.
Common situations: Typo or stale password after rotation in the client config; client library not aware this fork appends the password to the token; encoding differences (UTF-8 vs escaped characters); empty-password defaults differing between client and server builds.
Related errors
- auth method not supported.
- Shadowsocks password is not specified.
- invalid token + token
- Trojan password is not specified.
- socks 4 is not allowed when auth is required.
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/6523e5bdfa6a0802.
Report an issue: GitHub.