Reading arbitrary bytes from a lesser trusted context into a Bash variable in a higher trusted one (especially dom0) does already feel a bit iffy to me, even before considering how to use that variable later.
I don’t have a specific Bash vulnerability in mind, but here’s some paranoid thinking for example: Bash has the language construct ${#var}, which returns the length of the contents of var. That length is not about bytes but characters, so Bash must do character set related parsing - dealing with malformed Unicode and other horrors. Does it do all that only when the ${#var} construct is actually used, or is the length immediately precomputed upon reading into var? I hope it’s the former, but this seems like the kind of implementation detail that could be changed at any point for performance reasons. (Bash releases tend to be pretty casual about much more significant changes.)
To make reading untrusted data into a Bash variable safer, I use qvm-run --filter-escape-chars (or for VM-to-VM calls: qrexec-client-vm -t) to restrict the output to a subset of ASCII. If an even narrower set of characters is sufficient, I might pipe that output into tr, e.g. to throw away everything except numbers and lowercase letters: qvm-run --filter-escape-chars ... | LC_ALL=C tr -dc 0-9a-z. Maybe also append e.g. | head -c 1M to prevent the VM from sending gigabytes of data and exhausting all memory.
Exactly, every piece of data you avoid passing across a VM boundary is one that you don’t have to worry about sanitizing.
It’s possible to pass a command instead of a filename to qvm-backup and qvm-backup-restore. You could use that to generate the backup’s filename in dom0, then you don’t have to query it from sys-backup at all:
backup_file=/home/user/qubes-backup-$(date +'%Y-%m-%dT%H%M%S')
qvm-backup [...] "dd bs=128K iflag=fullblock conv=fsync of=$backup_file"
Those date and dd commands are copied based on what /etc/qubes-rpc/qubes.Backup does by default (if a filename is passed, not a command).