{"record":{"id":"4c50285dd3e72d55","repo":"projectdiscovery/nuclei","slug":"no-pl-option-tokens","errorCode":null,"errorMessage":"no PL option tokens","messagePattern":"no PL option tokens","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/js/libs/mssql/fingerprint.go","lineNumber":229,"sourceCode":"\t\toffset := binary.BigEndian.Uint16(response[position+1 : position+3])\n\t\tlength := binary.BigEndian.Uint16(response[position+3 : position+5])\n\t\tvar data []byte\n\t\tif length > 0 {\n\t\t\tstart := int(offset) + 8\n\t\t\tend := start + int(length)\n\t\t\tif start < 8 || end > len(response) {\n\t\t\t\treturn out, fmt.Errorf(\"invalid PL option data range\")\n\t\t\t}\n\t\t\tdata = response[start:end]\n\t\t}\n\t\ttokens = append(tokens, optionToken{token: token, offset: offset, length: length, data: data})\n\t\tposition += 5\n\t}\n\tif position >= len(response) || response[position] != tdsTerminator {\n\t\treturn out, fmt.Errorf(\"missing PL option terminator\")\n\t}\n\tif len(tokens) == 0 {\n\t\treturn out, fmt.Errorf(\"no PL option tokens\")\n\t}\n\tif tokens[0].token != plTokenVersion {\n\t\treturn out, fmt.Errorf(\"first PL option must be VERSION\")\n\t}\n\tif len(tokens[0].data) < 4 {\n\t\treturn out, fmt.Errorf(\"VERSION option too short\")\n\t}\n\n\tout.MajorVersion = int(tokens[0].data[0])\n\tout.MinorVersion = int(tokens[0].data[1])\n\tout.BuildNumber = int(tokens[0].data[2])<<8 | int(tokens[0].data[3])\n\tout.Version = fmt.Sprintf(\"%d.%d.%d\", out.MajorVersion, out.MinorVersion, out.BuildNumber)\n\n\tfor _, tok := range tokens[1:] {\n\t\tswitch tok.token {\n\t\tcase plTokenEncryption:\n\t\t\tif len(tok.data) > 0 {\n\t\t\t\tout.Encryption = int(tok.data[0])","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/js/libs/mssql/fingerprint.go#L211-L247","documentation":"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'.","triggerScenarios":"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.","commonSituations":"Honeypots and tarpits that answer any request with a tiny canned packet; corrupted fixtures in tests; protocols that echo a length-consistent empty structure.","solutions":["Treat as a non-MSSQL port: rely on mssql.IsMssql's false and skip mssql templates","Confirm with sqlcmd that the endpoint completes a real pre-login exchange","Capture the reply and check that byte 8 is 0xff (empty table) versus a real option token like 0x00","Use a different fingerprint technique (network probe, banner grab) for this host"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if (!mssql.IsMssql(host, port)) { return; }","typeGuard":null,"tryCatchPattern":"try { const info = mssql.FingerprintMssql(host, port); }\ncatch (e) { if (String(e).includes('no PL option tokens')) log('empty TDS option table: ' + host); else throw e; }","preventionTips":["Check the service with IsMssql before fingerprinting","An empty-but-terminated option table means an emulator — exclude the host from mssql logic"],"tags":["mssql","tds","protocol-parsing","fingerprint","empty-response","network"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}