{"record":{"id":"c4b6ed512b29a423","repo":"projectdiscovery/nuclei","slug":"response-too-short-for-tds-header","errorCode":null,"errorMessage":"response too short for TDS header","messagePattern":"response too short for TDS header","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/js/libs/mssql/fingerprint.go","lineNumber":181,"sourceCode":"\t}\n\treturn info, nil\n}\n\ntype preloginData struct {\n\tVersion         string\n\tMajorVersion    int\n\tMinorVersion    int\n\tBuildNumber     int\n\tEncryption      int\n\tEncryptionMode  string\n\tMars            bool\n\tInstanceMatches bool\n}\n\nfunc parsePreloginResponse(response []byte) (preloginData, error) {\n\tvar out preloginData\n\tif len(response) < 8 {\n\t\treturn out, fmt.Errorf(\"response too short for TDS header\")\n\t}\n\tif response[0] != tdsTypeTabularResult {\n\t\treturn out, fmt.Errorf(\"unexpected TDS type 0x%02x\", response[0])\n\t}\n\tif response[1] != tdsStatusEOM {\n\t\treturn out, fmt.Errorf(\"unexpected TDS status 0x%02x\", response[1])\n\t}\n\tpacketLength := int(binary.BigEndian.Uint16(response[2:4]))\n\tif len(response) != packetLength {\n\t\treturn out, fmt.Errorf(\"packet length mismatch: header=%d body=%d\", packetLength, len(response))\n\t}\n\n\ttype optionToken struct {\n\t\ttoken  byte\n\t\toffset uint16\n\t\tlength uint16\n\t\tdata   []byte\n\t}","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/js/libs/mssql/fingerprint.go#L163-L199","documentation":"Returned by parsePreloginResponse (and surfaced via FingerprintMssql wrapped in errNotMssql) when the response buffer is under 8 bytes, too short to contain a TDS header. In the live probe path this is largely defensive: fingerprintMssql already reads exactly 8 header bytes with io.ReadFull (a short reply fails earlier with io.ErrUnexpectedEOF), so this branch fires mainly for direct/internal callers passing truncated buffers.","triggerScenarios":"Unit tests or custom Go code calling parsePreloginResponse with a 0-7 byte slice; theoretically a zero-length body when packetLen==8 (header-only) still passes since len==8. Real short replies from the network surface as io errors before this check.","commonSituations":"Contributors writing tests for the mssql parser with hand-crafted short inputs; refactors that bypass the ReadFull header step.","solutions":["Feed the parser only complete responses: read the full 8-byte header (plus body per the length field) before parsing","In tests, use a realistic pre-login packet (>= 8 bytes starting with 04 01) as fixture","At the JS/template level, prefer FingerprintMssql/IsMssql which handle framing for you"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const info = mssql.FingerprintMssql(host, port);\n} catch (e) {\n  if (String(e).includes('not a mssql service')) return; // short/malformed TDS => skip\n  throw e;\n}","preventionTips":["Let FingerprintMssql do the framing; never call the internal parser with partial buffers","In Go tests, fixture packets must be complete pre-login responses (>= 8 bytes, 04 01 prefix)","Treat truncated replies the same as non-MSSQL answers at the template level"],"tags":["mssql","protocol","tds","parser","internal"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}