projectdiscovery/nuclei · warning

truncated PL option token

Error message

truncated PL option token

What it means

A TDS pre-login option table entry is a 5-byte header (option token byte + 2-byte offset + 2-byte length) and the table ends with a 0xff terminator. This error means fewer than 5 bytes remained before end of the response while a non-terminator byte was present, so an option header cannot be read completely. The reply is truncated mid-option and the pre-login data is unusable; FingerprintMssql re-wraps it as 'not a mssql service: truncated PL option token'.

Source

Thrown at pkg/js/libs/mssql/fingerprint.go:208

	if len(response) != packetLength {
		return out, fmt.Errorf("packet length mismatch: header=%d body=%d", packetLength, len(response))
	}

	type optionToken struct {
		token  byte
		offset uint16
		length uint16
		data   []byte
	}

	position := 8
	var tokens []optionToken
	for position < len(response) {
		if response[position] == tdsTerminator {
			break
		}
		if position+5 > len(response) {
			return out, fmt.Errorf("truncated PL option token")
		}
		token := response[position]
		offset := binary.BigEndian.Uint16(response[position+1 : position+3])
		length := binary.BigEndian.Uint16(response[position+3 : position+5])
		var data []byte
		if length > 0 {
			start := int(offset) + 8
			end := start + int(length)
			if start < 8 || end > len(response) {
				return out, fmt.Errorf("invalid PL option data range")
			}
			data = response[start:end]
		}
		tokens = append(tokens, optionToken{token: token, offset: offset, length: length, data: data})
		position += 5
	}
	if position >= len(response) || response[position] != tdsTerminator {
		return out, fmt.Errorf("missing PL option terminator")

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Confirm the service with mssql.IsMssql — it maps this parse failure to a clean false
  2. Check with a real TDS client (sqlcmd) that the server completes a pre-login handshake
  3. Capture the raw bytes and verify the option table ends with 0xff within the declared packet length
  4. If the target is behind a TLS-terminating proxy, note pre-login expects plaintext first; encryption is negotiated after, so a TLS-immediate endpoint yields garbage frames
Defensive patterns

Strategy: try-catch

Validate before calling

if (!mssql.IsMssql(host, port)) { log('not mssql, skip: ' + host); return; }

Try / catch

try { const info = mssql.FingerprintMssql(host, port); }
catch (e) { if (String(e).includes('truncated PL option token')) log('malformed TDS reply from ' + host); else throw e; }

Prevention

When it happens

Trigger: mssql.FingerprintMssql / mssql.IsMssql against a service that replies with a plausible 8-byte TDS header (type 0x04, status 0x01, consistent length) but whose option table is cut off without the 0xff terminator — crafted banners, protocol emulation honeypots, or truncated reads.

Common situations: Honeypots emulating MSSQL; misbehaving TDS proxies; custom fuzzing or unit tests feeding partial pre-login payloads; targeting non-MSSQL services that happen to start their reply with 0x04 0x01.

Related errors


AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15). Data as JSON: /api/errors/98562c6a675cec88. Report an issue: GitHub.