{"record":{"id":"38db38e67523872a","repo":"shadow1ng/fscan","slug":"mssql-truncated-info-token","errorCode":null,"errorMessage":"mssql: truncated info token","messagePattern":"mssql: truncated info token","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/services/mssql_raw.go","lineNumber":355,"sourceCode":"\tsize := int(binary.LittleEndian.Uint16(payload[pos : pos+2]))\n\tend := pos + 2 + size\n\tif size < 6 || end > len(payload) || pos+8 > len(payload) {\n\t\treturn mssqlRawError{}, pos, fmt.Errorf(\"mssql: invalid error token size\")\n\t}\n\tpos += 2\n\tnumber := int32(binary.LittleEndian.Uint32(payload[pos : pos+4]))\n\tpos += 4\n\tpos += 2\n\tmessage, next, err := mssqlReadUSVarChar(payload, pos)\n\tif err != nil {\n\t\treturn mssqlRawError{}, pos, err\n\t}\n\treturn mssqlRawError{number: number, message: message}, end, mssqlEnsureSkipBVarStrings(payload, next, end)\n}\n\nfunc mssqlSkipUSVarError(payload []byte, pos int) (int, error) {\n\tif pos+2 > len(payload) {\n\t\treturn pos, fmt.Errorf(\"mssql: truncated info token\")\n\t}\n\tsize := int(binary.LittleEndian.Uint16(payload[pos : pos+2]))\n\tend := pos + 2 + size\n\tif size < 6 || end > len(payload) || pos+8 > len(payload) {\n\t\treturn pos, fmt.Errorf(\"mssql: invalid info token size\")\n\t}\n\t_, _, err := mssqlReadUSVarChar(payload, pos+8)\n\treturn end, err\n}\n\nfunc mssqlEnsureSkipBVarStrings(payload []byte, pos, end int) error {\n\tfor i := 0; i < 2; i++ {\n\t\tif pos >= end {\n\t\t\treturn fmt.Errorf(\"mssql: truncated string in error token\")\n\t\t}\n\t\tlength := int(payload[pos]) * 2\n\t\tpos++\n\t\tif pos+length > end {","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/plugins/services/mssql_raw.go#L337-L373","documentation":"mssqlSkipUSVarError skips over an informational (INFO token, 0xAB) message in the login response, but fewer than 2 bytes remain, so the 2-byte token length header cannot be read. Like the ERROR-token variant, this is a boundary check that fails when the payload ends mid-token, signaling a truncated or corrupt server response rather than caller error.","triggerScenarios":"mssqlParseLoginTokens walks token stream and hits an INFO token whose position leaves less than 2 bytes in the payload (pos+2 > len(payload)).","commonSituations":"Network stack or proxy truncated the login response; server sent an informational message (e.g. 'changed database context') as the final bytes and the stream was cut; fuzzing or a non-TDS service responding on port 1433.","solutions":["Reconnect and retry; truncation is usually transient.","Confirm the endpoint is a real SQL Server speaking TDS on the configured port.","Enable packet capture to find what is truncating the TCP stream.","If reproducible with a specific server, report/patch the server-side token emission bug."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if len(payload)-pos < 2 {\n    return fmt.Errorf(\"INFO token header truncated at offset %d\", pos)\n}","typeGuard":"func hasInfoTokenHeader(payload []byte, pos int) bool {\n    return pos+2 <= len(payload)\n}","tryCatchPattern":"next, err := mssqlSkipUSVarError(payload, pos)\nif err != nil {\n    // truncated INFO token: response stream is corrupt\n    return fmt.Errorf(\"skipping INFO token failed: %w\", err)\n}","preventionTips":["Reconnect on truncation errors rather than reusing the connection state.","Confirm port 1433 (or your configured port) is served by actual TDS.","Check for packet loss on the path (MTU, flaky VPN).","Keep server and library TDS versions aligned."],"tags":["mssql","tds-protocol","truncated-payload","wire-parsing"],"backgroundTag":"unexpected-api-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"}