shadow1ng/fscan · error

mssql: truncated token

Error message

mssql: truncated token

What it means

mssqlSkipLen16 advances past a token whose body is a 2-byte length prefix (used for fixed-length login-response tokens). If fewer than 2 bytes remain, the length header itself cannot be read and the library throws 'truncated token'. It guards the token walker in mssqlParseLoginTokens against running off the end of a truncated payload.

Source

Thrown at plugins/services/mssql_raw.go:386

		if pos >= end {
			return fmt.Errorf("mssql: truncated string in error token")
		}
		length := int(payload[pos]) * 2
		pos++
		if pos+length > end {
			return fmt.Errorf("mssql: invalid string in error token")
		}
		pos += length
	}
	if pos+4 > end {
		return fmt.Errorf("mssql: truncated error line number")
	}
	return nil
}

func mssqlSkipLen16(payload []byte, pos int) (int, error) {
	if pos+2 > len(payload) {
		return pos, fmt.Errorf("mssql: truncated token")
	}
	size := int(binary.LittleEndian.Uint16(payload[pos : pos+2]))
	next := pos + 2 + size
	if next > len(payload) {
		return pos, fmt.Errorf("mssql: invalid token size")
	}
	return next, nil
}

func mssqlReadUSVarChar(payload []byte, pos int) (string, int, error) {
	if pos+2 > len(payload) {
		return "", pos, fmt.Errorf("mssql: truncated us varchar")
	}
	chars := int(binary.LittleEndian.Uint16(payload[pos : pos+2]))
	pos += 2
	size := chars * 2
	if pos+size > len(payload) {
		return "", pos, fmt.Errorf("mssql: invalid us varchar size")

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Retry the connection; transient truncation is the most common cause.
  2. Verify the port actually serves TDS SQL Server traffic.
  3. Increase proxy/LB idle timeouts if large login responses are being cut.
  4. Log the payload length and offset to confirm the response ended prematurely.

Example fix

// before: skip token without checking header availability
next, err := mssqlSkipLen16(payload, pos)
// after: bail out with context when the header is truncated
if len(payload)-pos < 2 {
    return fmt.Errorf("login response ended at offset %d, token header truncated", pos)
}
next, err := mssqlSkipLen16(payload, pos)
Defensive patterns

Strategy: try-catch

Validate before calling

if pos+2 > len(payload) {
    return fmt.Errorf("token header truncated: payload has %d bytes, need %d", len(payload)-pos, 2)
}

Type guard

func hasLen16Header(payload []byte, pos int) bool {
    return pos+2 <= len(payload)
}

Try / catch

next, err := mssqlSkipLen16(payload, pos)
if err != nil {
    conn.Close()
    return fmt.Errorf("truncated token in login response: %w", err)
}

Prevention

When it happens

Trigger: mssqlParseLoginTokens calls mssqlSkipLen16 for a token type whose payload starts at pos with pos+2 > len(payload).

Common situations: The login response was cut off mid-stream by a network drop or proxy timeout; a non-TDS service on port 1433 emitted a short blob; fuzzed server sends a payload ending right before a token header.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/eae317081601034b. Report an issue: GitHub.