Sandboxing user applications on linux with systemd or bubblewrap
Why sandbox?
The linux ecosystem is very powerful, with tons of libraries and programs for nearly any task you need to accomplish. These can be written by anyone and the barrier to entry is pretty low -- you can publish tools to your own website, share source code on forges like github, or send programs by email or chat. Many of these programs are scriptable, making it's tremendously easy to take anyone's code, start using it for your own projects, and automate them.
There is a downside though, and it's that the security model for your average linux desktop makes the risky assumption that any code you run is trusted. That is, any random program you download off of a sketchy part of the internet has full permission to read all your files, copy your ssh and api keys, upload everything to a remote server, and maintain persistence by using any of the many ways to automatically execute code without user awareness or elevated permissions.
This isn't unique to linux, and the same problem exists on windows (and on macos to a lesser degree). The default security policies are mainly used to protect users from each other, not protect the user from a malicious program they thought was a music player. The famous xkcd comic points this out:

Sandboxes are a good way to improve this by making it impossible (modulo vulnerabilities in the sandbox) to access anything that's not necessary for the program's operation.
Packaging with built-in sandboxing
The security situation on linux has been improving over the past few years, and it's now common for applications to be distributed with packaging formats like flatpak and snap, which are designed to confine applications to a sandbox to limit the impact of vulnerabilities. By default these enforce whatever permissions the developer implemented, but stricter ones can be implemented for both using flatpak override and snap connections. There are also graphical interfaces available like flatseal that make managing the permissions easier.
Flatpak and snap are pretty usefule for many user-facing applications, but not every program is or will be packaged with them. So it's important to be able to sandbox any application you use, rather than just some well-behaved ones.
The linux kernel has many built-in tools for this, like seccomp, landlock, and namespaces. Then there's the kernel security modules like selinux and apparmor which make it easier to apply rules accross an entire system. But from my perspective it's easier to sandbox individual tools on an ad-hoc basis than to create comprehensive security policies for them.
How to sandbox arbitrary user applications
Using systemd-run
Systemd has a lot of neat sandboxing features which aren't well known but can be very useful for this. You can get pretty far using systemd-run (which is already present on most linux systems) in a script like this:
#!/bin/sh
uid="$(id -u)"
gid="$(id -g)"
cwd="$(pwd -P)"
sudo systemd-run --system --pty --same-dir --wait --collect --service-type=exec \
--uid="$uid" \
--gid="$gid" \
-p "TemporaryFileSystem=/:ro /tmp" \
-p "BindReadOnlyPaths=-/bin -/sbin -/usr/bin -/usr/sbin -/lib -/lib64 -/usr/lib -/usr/lib64 -/usr/libexec" \
-p "BindPaths=$cwd" \
-p "PrivateNetwork=true" \
-p "PrivateDevices=true" \
-p "PrivateIPC=true" \
-p "RestrictNamespaces=true" \
-p "RestrictSUIDSGID=true" \
-p "CapabilityBoundingSet=" \
"$@"
Which creates a blank filesystem with no network or device access and only bind mounts the specified files, so the program won't be able to access anything that hasn't been explicitly mentioned.
Unfortunately TemporaryFileSystem require running as a system instance of the
service manager rather than per-user instance, so that will generally mean
running as root (hence sudo). One approach is to create a suid binary that does
the same without needing sudo.
Using bubblewrap
You could also install bubblewrap and use it pretty similarly to systemd-run, and it has the added benefit that you won't need to use sudo if unprivileged user namespaces are allowed by your kernel (which is usually the case).
#!/bin/sh
cwd="$(pwd -P)"
bwrap --new-session --die-with-parent \
--tmpfs /tmp \
--ro-bind-try /bin /bin \
--ro-bind-try /sbin /sbin \
--ro-bind-try /usr/bin /usr/bin \
--ro-bind-try /usr/sbin /usr/sbin \
--ro-bind-try /lib /lib \
--ro-bind-try /lib64 /lib64 \
--ro-bind-try /usr/lib /usr/lib \
--ro-bind-try /usr/lib64 /usr/lib64 \
--ro-bind-try /usr/libexec /usr/libexec \
--bind "$cwd" "$cwd" \
--dev-bind /dev/null /dev/null \
--dev-bind /dev/zero /dev/zero \
--dev-bind /dev/random /dev/random \
--unshare-net \
--unshare-ipc \
--cap-drop ALL \
--chdir "$cwd" \
"$@"