{"record":{"id":"25a0a58168595048","repo":"shadow1ng/fscan","slug":"short-fragment-payload-w","errorCode":null,"errorMessage":"short fragment payload: %w","messagePattern":"short fragment payload: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/services/nfs.go","lineNumber":236,"sourceCode":"\t\t}\n\t}\n\treturn exports\n}\n\nfunc readRPCFragment(conn interface {\n\tRead([]byte) (int, error)\n}, maxPayload int) ([]byte, error) {\n\tvar header [4]byte\n\tif _, err := io.ReadFull(conn, header[:]); err != nil {\n\t\treturn nil, fmt.Errorf(\"short fragment header: %w\", err)\n\t}\n\tsize := int(binary.BigEndian.Uint32(header[:]) & 0x7fffffff)\n\tif size <= 0 || size > maxPayload {\n\t\treturn nil, fmt.Errorf(\"invalid fragment size: %d\", size)\n\t}\n\tpayload := make([]byte, size)\n\tif _, err := io.ReadFull(conn, payload); err != nil {\n\t\treturn nil, fmt.Errorf(\"short fragment payload: %w\", err)\n\t}\n\treturn payload, nil\n}\n\nfunc (p *NFSPlugin) buildRPCCall(xid, program, version, procedure uint32, data []byte) []byte {\n\tauthNone := []byte{0, 0, 0, 0, 0, 0, 0, 0} // AUTH_NONE flavor=0, len=0\n\n\tbuf := make([]byte, 0, 40+len(data))\n\tbuf = binary.BigEndian.AppendUint32(buf, xid)\n\tbuf = binary.BigEndian.AppendUint32(buf, 0) // CALL\n\tbuf = binary.BigEndian.AppendUint32(buf, 2) // RPC version\n\tbuf = binary.BigEndian.AppendUint32(buf, program)\n\tbuf = binary.BigEndian.AppendUint32(buf, version)\n\tbuf = binary.BigEndian.AppendUint32(buf, procedure)\n\tbuf = append(buf, authNone...) // credentials\n\tbuf = append(buf, authNone...) // verifier\n\tbuf = append(buf, data...)\n\treturn buf","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/plugins/services/nfs.go#L218-L254","documentation":"After validating the fragment size, readRPCFragment reads exactly `size` payload bytes with io.ReadFull. This error wraps any short read: the connection closed or delivered fewer bytes than the fragment header promised, so the RPC fragment is incomplete and cannot be parsed.","triggerScenarios":"rpcNullCall or getExports receives a header declaring N bytes but the peer closes the connection or stalls mid-fragment; TestNFSReadRPCFragmentRejectsInvalidSize also exercises this path indirectly.","commonSituations":"Server crashed or reset the connection mid-response; network timeout/firewall dropped the stream; target is not a real NFS server and closed after the first bytes; read deadline expired.","solutions":["Retry the scan — transient connection resets are common on loaded servers","Confirm the target actually speaks the RPC record-marking protocol on this port","Check firewall/keepalive settings that may cut idle or slow TCP connections","Add or increase the connection read deadline if slow servers truncate responses"],"exampleFix":"// before\nif _, err := io.ReadFull(conn, payload); err != nil {\n    return nil, fmt.Errorf(\"short fragment payload: %w\", err)\n}\n// after\nif _, err := io.ReadFull(conn, payload); err != nil {\n    return nil, fmt.Errorf(\"short fragment payload: expected %d bytes: %w\", size, err)\n}","handlingStrategy":"retry","validationCode":"// pre-check: ensure connection is alive before reading\nif deadline, ok := conn.(interface{ SetReadDeadline(time.Time) error }); ok {\n    _ = deadline.SetReadDeadline(time.Now().Add(5 * time.Second))\n}","typeGuard":null,"tryCatchPattern":"payload, err := readRPCFragment(conn)\nif err != nil {\n    if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) {\n        return retryWithNewConnection() // truncated stream: reconnect, do not reuse\n    }\n    return err\n}","preventionTips":["Set reasonable read deadlines to fail fast on stalled servers","Always retry fragmented RPC reads on a fresh connection — partial fragments poison the stream","Check network path (firewalls, NAT timeouts) if truncation is recurring"],"tags":["network","nfs","rpc","truncated-response"],"backgroundTag":"network-request-failed","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"}