{"record":{"id":"4898c170a1630d42","repo":"projectdiscovery/nuclei","slug":"first-pl-option-must-be-version","errorCode":null,"errorMessage":"first PL option must be VERSION","messagePattern":"first PL option must be VERSION","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/js/libs/mssql/fingerprint.go","lineNumber":232,"sourceCode":"\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])\n\t\t\t\tout.EncryptionMode = encryptionModeName(tok.data[0])\n\t\t\t}\n\t\tcase plTokenInstOpt:","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/js/libs/mssql/fingerprint.go#L214-L250","documentation":"The TDS pre-login specification requires VERSION (token 0x00) to be the first option in the table; the parser reads major/minor/build from its data. This error fires when tokens[0].token is anything other than 0x00 (e.g. ENCRYPTION 0x01 or INSTANCE 0x02 first), which no real SQL Server sends. It is one of the errNotMssql-wrapped parse failures, so mssql.IsMssql maps it to false and mssql.FingerprintMssql returns 'not a mssql service: first PL option must be VERSION'.","triggerScenarios":"mssql.FingerprintMssql / IsMssql against a reply whose option table starts with a non-VERSION token — non-standard TDS implementations, emulators, or corrupted/shifted byte streams where offsets desynchronize the table.","commonSituations":"Custom or embedded TDS-ish servers; honeypots; unit fixtures with options in the wrong order; replies where an earlier field shifted the parse position so the table is read from the wrong offset.","solutions":["Verify with mssql.IsMssql / a genuine TDS client before fingerprinting","Hex-dump the response and decode the option table manually to see which token actually appears at byte 8","If the server is a legitimate SQL Server variant, compare its raw reply against a stock instance to find the framing divergence","Fall back to version detection via other probes (e.g. post-auth SELECT @@version once credentials exist)"],"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('first PL option must be VERSION')) log('non-conforming TDS peer: ' + host); else throw e; }","preventionTips":["Rely on IsMssql for classification; spec-violation replies are a definitive negative","Compare failing hosts' raw replies against a stock SQL Server to diagnose emulators"],"tags":["mssql","tds","protocol-parsing","fingerprint","spec-violation","network"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}