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

  1. Use mssql.IsMssql to classify the port first; false means the reply failed MSSQL validation
  2. 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
  3. Cross-check with sqlcmd or a known-good TDS client before trusting the endpoint
  4. 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

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


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