projectdiscovery/nuclei · warning
invalid PL option data range
Error message
invalid PL option data range
What it means
Each pre-login option header points at its data via an offset (relative to the 8-byte TDS header) and a length; the window response[offset+8 : offset+8+length] must lie fully inside the packet. This error fires when that window starts before byte 8 or runs past the end of the response — the option table references data that does not exist. It is one of the errNotMssql-wrapped parse failures, so IsMssql turns it into (false, nil) while FingerprintMssql returns 'not a mssql service: invalid PL option data range'.
Source
Thrown at pkg/js/libs/mssql/fingerprint.go:218
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")
}
if len(tokens) == 0 {
return out, fmt.Errorf("no PL option tokens")
}
if tokens[0].token != plTokenVersion {
return out, fmt.Errorf("first PL option must be VERSION")
}
if len(tokens[0].data) < 4 {
return out, fmt.Errorf("VERSION option too short")
}View on GitHub (pinned to 265b3a3dec)
Solutions
- Use mssql.IsMssql to classify the port first; false means the reply failed MSSQL validation
- Capture the reply with tcpdump and manually decode the option table (5-byte entries after byte 8) checking each offset+8+length against the packet size
- Cross-check with sqlcmd or a known-good TDS client before trusting the endpoint
- Fall back to banner/nmap service detection for this target
Defensive patterns
Strategy: try-catch
Validate before calling
if (!mssql.IsMssql(host, port)) { return; } Try / catch
try { const info = mssql.FingerprintMssql(host, port); }
catch (e) { if (String(e).includes('invalid PL option data range')) log('bad TDS option table from ' + host); else throw e; } Prevention
- Gate fingerprinting on a positive IsMssql result
- Treat bounds-check failures as non-MSSQL classification, not transient errors
- Avoid retrying parse failures — they are deterministic per reply bytes
When it happens
Trigger: mssql.FingerprintMssql / IsMssql against a replying service whose option offsets/lengths point outside the packet: corrupt banners, non-TDS protocols emitting 0x04 0x01 prefixes, or hand-built pre-login responses with wrong offset math.
Common situations: Service emulation (honeypots, tarpits) on 1433; unit tests with malformed fixture packets; off-by-one bugs in custom TDS implementations being scanned.
Related errors
- VERSION option too short
- packet length mismatch: header=%d body=%d
- truncated PL option token
- missing PL option terminator
- no PL option tokens
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/48a323b5fe72df5f.
Report an issue: GitHub.