projectdiscovery/nuclei · warning

no PL option tokens

Error message

no PL option tokens

What it means

A conforming TDS pre-login response must contain at least one option entry before the 0xff terminator; the very first option must be VERSION. This error means the parser saw the 0xff terminator immediately at byte 8, so the option table is empty and no version/encryption data exists. It is wrapped with errNotMssql (fingerprint.go:147-149), so mssql.IsMssql reports false and mssql.FingerprintMssql reports 'not a mssql service: no PL option tokens'.

Source

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

		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")
	}

	out.MajorVersion = int(tokens[0].data[0])
	out.MinorVersion = int(tokens[0].data[1])
	out.BuildNumber = int(tokens[0].data[2])<<8 | int(tokens[0].data[3])
	out.Version = fmt.Sprintf("%d.%d.%d", out.MajorVersion, out.MinorVersion, out.BuildNumber)

	for _, tok := range tokens[1:] {
		switch tok.token {
		case plTokenEncryption:
			if len(tok.data) > 0 {
				out.Encryption = int(tok.data[0])

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Treat as a non-MSSQL port: rely on mssql.IsMssql's false and skip mssql templates
  2. Confirm with sqlcmd that the endpoint completes a real pre-login exchange
  3. Capture the reply and check that byte 8 is 0xff (empty table) versus a real option token like 0x00
  4. Use a different fingerprint technique (network probe, banner grab) for this host
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('no PL option tokens')) log('empty TDS option table: ' + host); else throw e; }

Prevention

When it happens

Trigger: mssql.FingerprintMssql / IsMssql against a service that returns a well-framed TDS packet whose entire payload after the 8-byte header is just the 0xff terminator — e.g. minimal emulators or probes designed to ack without data.

Common situations: Honeypots and tarpits that answer any request with a tiny canned packet; corrupted fixtures in tests; protocols that echo a length-consistent empty structure.

Related errors


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