shadow1ng/fscan · error
mssql: unexpected login token 0x%02x
Error message
mssql: unexpected login token 0x%02x
What it means
The login response contained a TDS token the parser does not understand. This minimal raw-login implementation only handles error/info/envchange/loginack/done tokens, so any other token in the login response aborts parsing.
Source
Thrown at plugins/services/mssql_raw.go:327
if err != nil {
return false, err
}
pos = next
case tdsTokenLoginAck:
next, err := mssqlSkipLen16(payload, pos)
if err != nil {
return false, err
}
result.sawLoginAck = true
pos = next
case tdsTokenDone, tdsTokenDoneProc, tdsTokenDoneInProc:
if pos+12 > len(payload) {
return false, fmt.Errorf("mssql: truncated done token")
}
status := binary.LittleEndian.Uint16(payload[pos : pos+2])
return status&(tdsDoneError|tdsDoneSrvError) == 0, nil
default:
return false, fmt.Errorf("mssql: unexpected login token 0x%02x", token)
}
}
return false, nil
}
func mssqlParseErrorToken(payload []byte, pos int) (mssqlRawError, int, error) {
if pos+2 > len(payload) {
return mssqlRawError{}, pos, fmt.Errorf("mssql: truncated error token")
}
size := int(binary.LittleEndian.Uint16(payload[pos : pos+2]))
end := pos + 2 + size
if size < 6 || end > len(payload) || pos+8 > len(payload) {
return mssqlRawError{}, pos, fmt.Errorf("mssql: invalid error token size")
}
pos += 2
number := int32(binary.LittleEndian.Uint32(payload[pos : pos+4]))
pos += 4
pos += 2View on GitHub (pinned to 95cc12e753)
Solutions
- Check whether the server demands SSPI/Kerberos — if so, SQL auth cannot complete without implementing token 0xED handling; use go-mssqldb with Integrated Security instead.
- Add a case for the reported token type (it is printed in the error) if it is benign and can be safely skipped.
- Verify TDS version negotiation — some tokens only appear at higher TDS versions.
- Capture the stream and confirm the token byte is where parsing believes it is (a prior token mis-skip can desynchronize the walk).
Example fix
// before
default:
return false, fmt.Errorf("mssql: unexpected login token 0x%02x", token)
// after
case 0xed: // SSPI — not supported by this raw client
return false, fmt.Errorf("mssql: server requested SSPI authentication; use SQL auth or a full driver")
default:
return false, fmt.Errorf("mssql: unexpected login token 0x%02x", token) Defensive patterns
Strategy: try-catch
Try / catch
_, err := mssqlRawLogin(ctx, host, port, user, pass, timeout)
if err != nil {
var tok byte
if n, _ := fmt.Sscanf(err.Error(), "mssql: unexpected login token 0x%02x", &tok); n == 1 && tok == 0xed {
return fmt.Errorf("server requires SSPI auth; use a full driver")
}
return err
} Prevention
- Use SQL authentication accounts (not Windows-integrated) when probing with this raw client.
- Extend the token switch when new server features emit extra tokens.
- Read the token hex in the error message to identify what the server sent.
When it happens
Trigger: mssqlParseLoginTokens' default branch fires on token bytes such as 0x81 (COLMETADATA), 0x81/0xA9/0xA8 result tokens, or SSPI (0xED) — typically when the server wants integrated auth or returns result sets during login.
Common situations: Windows/SSPI authentication requested by the server (token 0xED); servers emitting features this minimal client didn't negotiate; truly desynchronized/garbage streams.
Related errors
- mssql: unexpected login response packet type %d
- mssql: login acknowledgement not received
- mssql: invalid prelogin response packet type %d
- mssql: prelogin response missing encryption field
- mssql: truncated done token
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/a2f1ebe2a3be1b19.
Report an issue: GitHub.