It's not easy. Just getting the mounts right is not sufficient. You also need to consider syscalls. E.g. TIOCSTI is permitted by default and allows an easy sandbox escape. See [0]CVE-2017-5226. TIOCLINUX can also allow sandbox escapes.
This can be prevented with the --new-session option, but that breaks interactive terminals, e.g. it causes ctrl-C to restore input to the parent shell while simultaneously running the child shell on the same terminal with the same inputs, which makes it unusable.
The alternative is compiling a seccomp BPF program to filter the syscalls, and loading it with the --seccomp option, but even this is non-trivial, e.g. see [1]CVE-2019-10063. This is also a case of "enumerating badness"; there's no guarantee that other syscalls are not also exploitable.
I've noticed a trend of adding N deeply intertwined features which then interact in N! different ways and no one bothers to define rigorous semantics for them. And then you have to get a PhD in Linux just to understand whether your system is vulnerable when you use POSIX message queues inside a FUSE filesystem inside an unprivileged user namespace inside chroot inside setarch running in 9 nested terminal sessions.
I think I'm starting to understand why some people swear by the BSDs.
Edit: just checked and OpenBSD has indeed removed TIOCSTI in 2017.
0% design and 100% scratch-my-itch tack on another feature.
Sandboxing a program that needs graphics performance anywhere near 10% of what the hardware is capable of is, at the moment, as we're stuck with X11 and growing gray hair waiting for Wayland to become a viable alternative, literally impossible.
Firejail does provide pre-made solutions like running nested X servers, which can sandbox graphical applications at insane resource costs, such that you might as well just run a full virtual machine.
Mount namespaces are security theater if you're giving access to X11, Pipewire, the SSH agent, the GPG agent, the dbus session bus, and god knows what else.
All you need to do is share the compositors socket and /dev/dri with the "container" and it "just works" for me!
I do not have xwayland enabled either, all of the software I use is wayland native!