shadow1ng/fscan · error

mssql: truncated string in error token

Error message

mssql: truncated string in error token

What it means

mssqlEnsureSkipBVarStrings walks the two BVarChar strings (server name and error message) inside a TDS ERROR token. It throws this when the cursor has already reached the token end (pos >= end) before reading one of those strings, meaning the token is shorter than the spec requires. This is a defensive check against malformed ERROR tokens.

Source

Thrown at plugins/services/mssql_raw.go:369

}

func mssqlSkipUSVarError(payload []byte, pos int) (int, error) {
	if pos+2 > len(payload) {
		return pos, fmt.Errorf("mssql: truncated info 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 pos, fmt.Errorf("mssql: invalid info token size")
	}
	_, _, err := mssqlReadUSVarChar(payload, pos+8)
	return end, err
}

func mssqlEnsureSkipBVarStrings(payload []byte, pos, end int) error {
	for i := 0; i < 2; i++ {
		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")
	}

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Capture and hex-dump the login response to confirm which string is missing from the ERROR token.
  2. Retry the login; if reproducible, treat the server as misbehaving and report it.
  3. Check for proxies or firewalls rewriting the TDS payload in transit.
  4. In callers, treat this as a fatal parse error and close the connection rather than resuming at a guessed offset.
Defensive patterns

Strategy: validation

Validate before calling

end := pos + 2 + int(binary.LittleEndian.Uint16(payload[pos:pos+2]))
if pos+8+1+2+1+2+4 > end {
    return fmt.Errorf("ERROR token too small to contain header+strings+line number")
}

Try / catch

if err := mssqlEnsureSkipBVarStrings(payload, pos, end); err != nil {
    return fmt.Errorf("incomplete ERROR token (offset %d..%d): %w", pos, end, err)
}

Prevention

When it happens

Trigger: mssqlParseErrorToken finishes the fixed header and calls mssqlEnsureSkipBVarStrings, but after skipping earlier fields the position equals or exceeds the token end before both length-prefixed strings are consumed.

Common situations: Server (or man-in-the-middle) emits an ERROR token with missing server-name/message strings; fuzzer probes sending minimal-length tokens; corruption from a buggy TCP middlebox dropping bytes inside the token.

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/55510294461a53ca. Report an issue: GitHub.