{"record":{"id":"68774482dc79618c","repo":"projectdiscovery/nuclei","slug":"packet-length-mismatch-header-d-body-d","errorCode":null,"errorMessage":"packet length mismatch: header=%d body=%d","messagePattern":"packet length mismatch: header=(.+?) body=(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/js/libs/mssql/fingerprint.go","lineNumber":191,"sourceCode":"\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}\n\n\tposition := 8\n\tvar tokens []optionToken\n\tfor position < len(response) {\n\t\tif response[position] == tdsTerminator {\n\t\t\tbreak\n\t\t}\n\t\tif position+5 > len(response) {\n\t\t\treturn out, fmt.Errorf(\"truncated PL option token\")\n\t\t}","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/js/libs/mssql/fingerprint.go#L173-L209","documentation":"Thrown while parsing a TDS pre-login response in nuclei' mssql JS library. The 16-bit big-endian packet length at bytes 2:4 of the reply must equal the total number of bytes buffered for the response; when they differ, the packet is self-inconsistent and cannot be trusted. In the current wiring (fingerprintMssql reads exactly packetLen bytes), the check is defensive and fires on replies from proxies/non-standard TDS peers or future multi-packet handling. When it escapes, FingerprintMssql wraps it as 'not a mssql service: ...' (fingerprint.go:147-149).","triggerScenarios":"Calling mssql.FingerprintMssql(host, port) (or IsMssql, which maps it to false) against a TCP service whose reply's declared TDS length field disagrees with the bytes actually delivered — e.g. a load balancer, an RDP/other service on 1433, or a TDS server splitting the pre-login reply across packets.","commonSituations":"Scanning a host where port 1433 is actually fronted by a proxy or runs another protocol; hardened/patched SQL Server appliances with non-standard TDS framing; test harnesses feeding hand-crafted pre-login buffers.","solutions":["Verify the port really speaks TDS: nmap -sV -p 1433 or mssql.IsMssql(host, port) — a false result means 'not MSSQL', not a bug","If the target is genuinely SQL Server, capture the raw reply (info.Raw on success, or tcpdump) and compare the length field at offset 2:4 with the captured packet size","Treat it as a fingerprint mismatch: rely on other service detection (banner, SSL, network probes) instead of the mssql fingerprint","If writing Go code that calls parsePreloginResponse directly, ensure you buffer exactly the declared length before parsing"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const isMssql = mssql.IsMssql(host, port);\nif (!isMssql) { log(host + ':' + port + ' is not mssql'); return; }","typeGuard":null,"tryCatchPattern":"try {\n  const info = mssql.FingerprintMssql(host, port);\n} catch (e) {\n  // parse failures surface as 'not a mssql service: <detail>'\n  if (String(e).includes('not a mssql service')) { log('non-mssql target: ' + host); }\n  else { throw e; }\n}","preventionTips":["Call mssql.IsMssql before FingerprintMssql — parse failures map to a clean false","Restrict mssql templates to ports already identified as SQL Server","Keep a try/catch around fingerprint calls in templates so one bad target does not abort the run"],"tags":["mssql","tds","protocol-parsing","fingerprint","network","go"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}