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
- Confirm the service with mssql.IsMssql — it maps this parse failure to a clean false
- Check with a real TDS client (sqlcmd) that the server completes a pre-login handshake
- Capture the raw bytes and verify the option table ends with 0xff within the declared packet length
- 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
- Probe with IsMssql first — it swallows errNotMssql-wrapped parse failures
- Do not point mssql templates at unverified ports
- Capture replies from persistent offenders to build a skip-list
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
- packet length mismatch: header=%d body=%d
- invalid PL option data range
- missing PL option terminator
- no PL option tokens
- first PL option must be VERSION
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/98562c6a675cec88.
Report an issue: GitHub.