{"record":{"id":"d300071de018168c","repo":"shadow1ng/fscan","slug":"mssql-invalid-us-varchar-size","errorCode":null,"errorMessage":"mssql: invalid us varchar size","messagePattern":"mssql: invalid us varchar size","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/services/mssql_raw.go","lineNumber":404,"sourceCode":"\t\treturn pos, fmt.Errorf(\"mssql: truncated token\")\n\t}\n\tsize := int(binary.LittleEndian.Uint16(payload[pos : pos+2]))\n\tnext := pos + 2 + size\n\tif next > len(payload) {\n\t\treturn pos, fmt.Errorf(\"mssql: invalid token size\")\n\t}\n\treturn next, nil\n}\n\nfunc mssqlReadUSVarChar(payload []byte, pos int) (string, int, error) {\n\tif pos+2 > len(payload) {\n\t\treturn \"\", pos, fmt.Errorf(\"mssql: truncated us varchar\")\n\t}\n\tchars := int(binary.LittleEndian.Uint16(payload[pos : pos+2]))\n\tpos += 2\n\tsize := chars * 2\n\tif pos+size > len(payload) {\n\t\treturn \"\", pos, fmt.Errorf(\"mssql: invalid us varchar size\")\n\t}\n\treturn mssqlDecodeUCS2(payload[pos : pos+size]), pos + size, nil\n}\n\nfunc mssqlWritePacket(w io.Writer, packetType byte, payload []byte) error {\n\tif len(payload)+8 > 0xffff {\n\t\treturn fmt.Errorf(\"mssql: packet too large\")\n\t}\n\theader := []byte{packetType, tdsStatusEOM, 0, 0, 0, 0, 1, 0}\n\tbinary.BigEndian.PutUint16(header[2:4], uint16(len(payload)+8))\n\tif _, err := w.Write(header); err != nil {\n\t\treturn err\n\t}\n\t_, err := w.Write(payload)\n\treturn err\n}\n\nfunc mssqlReadMessage(r io.Reader) (byte, []byte, error) {","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/plugins/services/mssql_raw.go#L386-L422","documentation":"mssqlReadUSVarChar parses a TDS USHORT-length (UCS-2/UTF-16) string from a raw packet payload. After reading the 2-byte character count it computes the byte size as chars*2 and verifies those bytes exist in the payload. If they do not fit within the remaining buffer, it refuses to slice out of bounds and returns this error.","triggerScenarios":"Parsing a TDS token (e.g. an ERROR token via mssqlParseErrorToken, or mssqlSkipUSVarError) whose embedded usvarchar length field claims more bytes than the packet actually contains — typically a malformed, truncated, or maliciously crafted server response.","commonSituations":"Talking to a non-MSSQL or middleware service that emits broken TDS streams; a packet truncated by a proxy or NAT; fuzzing/pen-testing a fake SQL Server that returns malformed ERROR tokens.","solutions":["Verify the server is a genuine SQL Server speaking correct TDS; a wrong service on the port yields garbage payloads.","Treat the stream as untrusted: this error indicates corrupt input — drop the connection and re-connect if transient.","If parsing custom TDS tokens, confirm the token length field was honored before calling mssqlReadUSVarChar (offset advanced by the declared token size).","Update the plugin/parser version — earlier token parsers may mis-offset subsequent usvarchar reads."],"exampleFix":"// before\nchars := int(binary.LittleEndian.Uint16(payload[pos : pos+2]))\npos += 2\nsize := chars * 2\nif pos+size > len(payload) {\n    return \"\", pos, fmt.Errorf(\"mssql: invalid us varchar size\")\n}\n// after\nchars := int(binary.LittleEndian.Uint16(payload[pos : pos+2]))\npos += 2\nsize := chars * 2\nif size < 0 || pos+size > len(payload) {\n    return \"\", pos, fmt.Errorf(\"mssql: invalid us varchar size (need %d bytes, have %d)\", size, len(payload)-pos)\n}","handlingStrategy":"validation","validationCode":"func canReadUSVarChar(payload []byte, pos int) bool {\n    if pos+2 > len(payload) {\n        return false\n    }\n    chars := int(binary.LittleEndian.Uint16(payload[pos : pos+2]))\n    return pos+2+chars*2 <= len(payload)\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    if strings.Contains(err.Error(), \"invalid us varchar size\") {\n        // malformed TDS token: drop connection, mark target untrusted\n    }\n}","preventionTips":["Never parse TDS payloads from unverified services; confirm the peer speaks TDS first.","Honor token-level length fields before advancing into embedded strings.","Cap accumulated parse sizes to catch truncated streams early.","Reconnect rather than resynchronizing a corrupted stream."],"tags":["mssql","tds","protocol-parsing","malformed-input"],"backgroundTag":"unexpected-response-shape","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}