#!/usr/bin/env sh # Sandbox wrapper for tools that parse data from untrusted network # sources (yt-dlp, streamlink). The threat model is RCE in a # subtitle / muxer / extractor that walks the user's home directory # looking for SSH/GPG keys, password store, cloud tokens, etc. # # Compromise: most of the system is still reachable (--bind / /), so # Wayland, PipeWire, DBus, GPU, hardware accel and config files all # work transparently; the sandbox only tmpfs-shadows known-sensitive # directories so a compromised parser cannot read them. # # (mpv itself is run as the io.mpv.Mpv flatpak, which is its own # sandbox — no extra bwrap wrapper needed.) # # Set SANDBOX=0 to bypass entirely for a single invocation: # SANDBOX=0 streamlink weird-stream-url # # Usage (called by the per-tool wrappers): _sandbox-net-parser /usr/bin/yt-dlp "$@" set -eu if [ "${SANDBOX:-1}" = "0" ]; then bin=$1 shift exec "$bin" "$@" fi if ! command -v bwrap >/dev/null 2>&1; then printf '%s: bwrap not installed; falling back to direct exec\n' "$0" >&2 bin=$1 shift exec "$bin" "$@" fi bin=$1 shift # Prevent re-entry: any tool spawned inside the sandbox that resolves # `yt-dlp`/`streamlink` via PATH must find the real binary, not another # wrapper that would try to nest a second bwrap and fail. Strip # ~/.local/bin and nix-profile/bin from PATH inside the namespace. inner_path='/usr/local/sbin:/usr/local/bin:/usr/bin' exec bwrap \ --bind / / \ --dev-bind /dev /dev \ --proc /proc \ --tmpfs /root \ --tmpfs "$HOME/.ssh" \ --tmpfs "$HOME/.gnupg" \ --tmpfs "$HOME/.password-store" \ --tmpfs "$HOME/.config/gh" \ --tmpfs "$HOME/.config/op" \ --tmpfs "$HOME/.aws" \ --tmpfs "$HOME/.local/share/keyrings" \ --tmpfs "$HOME/.local/share/pass" \ --setenv PATH "$inner_path" \ --die-with-parent \ --new-session \ -- "$bin" "$@"