{"record":{"id":"badf8eea9c143eec","repo":"shadow1ng/fscan","slug":"truncated-verifier-padding","errorCode":null,"errorMessage":"truncated verifier padding","messagePattern":"truncated verifier padding","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/services/nfs.go","lineNumber":155,"sourceCode":"\treplyStatus := binary.BigEndian.Uint32(reply[8:12])\n\tif replyStatus != 0 { // MSG_ACCEPTED\n\t\treturn nil, fmt.Errorf(\"reply rejected\")\n\t}\n\n\t// Skip auth verifier\n\toffset := 12\n\tif offset+8 > len(reply) {\n\t\treturn nil, fmt.Errorf(\"truncated\")\n\t}\n\t// verifier flavor + length\n\tverifierLen := binary.BigEndian.Uint32(reply[offset+4 : offset+8])\n\tif verifierLen > uint32(len(reply)-offset-8) {\n\t\treturn nil, fmt.Errorf(\"truncated verifier\")\n\t}\n\toffset += 8 + int(verifierLen)\n\tif pad := (4 - verifierLen%4) % 4; pad > 0 {\n\t\tif int(pad) > len(reply)-offset {\n\t\t\treturn nil, fmt.Errorf(\"truncated verifier padding\")\n\t\t}\n\t\toffset += int(pad)\n\t}\n\n\t// Accept status\n\tif offset+4 > len(reply) {\n\t\treturn nil, fmt.Errorf(\"truncated\")\n\t}\n\tacceptStatus := binary.BigEndian.Uint32(reply[offset : offset+4])\n\tif acceptStatus != 0 { // SUCCESS\n\t\treturn nil, fmt.Errorf(\"accept status: %d\", acceptStatus)\n\t}\n\toffset += 4\n\n\treturn p.parseExportList(reply[offset:]), nil\n}\n\nfunc (p *NFSPlugin) parseExportList(data []byte) []string {","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/plugins/services/nfs.go#L137-L173","documentation":"XDR pads opaque verifier data to a 4-byte boundary. After skipping the verifier, getExports checks that the padding bytes are present in the reply; if not, the record is truncated and the accept-status field can't be read safely. This is the padding-specific sibling of the \"truncated verifier\" check (a known corner case exercised by TestNFSGetExportsHandlesVerifierPadding).","triggerScenarios":"Calling Scan or TestNFSGetExportsHandlesVerifierPadding when the reply ends exactly at verifierLen with fewer than (4 - verifierLen%4)%4 padding bytes remaining.","commonSituations":"Server implementations that omit XDR padding (a spec bug); truncated last TCP segment; crafted replies from fuzzed targets.","solutions":["Retry against the host to rule out transient truncation","Verify with showmount -e whether the server is generally functional","Flag the host as non-conformant (missing XDR padding) and continue scanning","Capture the raw reply and compare against a known-good mountd EXPORT reply"],"exampleFix":"// before\n// server omits padding after an 11-byte verifier\n// after\n// pad-tolerant fallback: treat missing final padding as end-of-reply\nif pad > 0 && int(pad) > len(reply)-offset {\n    // tolerate missing trailing pad only if no further data expected\n}","handlingStrategy":"fallback","validationCode":"null","typeGuard":"null","tryCatchPattern":"exports, err := getExports(conn, xid)\nif err != nil && strings.Contains(err.Error(), \"truncated verifier padding\") {\n    // tolerate non-conformant servers missing trailing XDR pad\n    exports, err = getExportsLenient(conn, xid)\n}","preventionTips":["Prefer strict parsing first, lenient parsing only as fallback","Note hosts that omit XDR padding as implementation bugs","Cross-check with showmount -e before trusting lenient results"],"tags":["network","rpc","xdr","padding"],"backgroundTag":"invalid-json-response","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"}