use std::fs; use std::path::{Path, PathBuf}; use crate::SandboxError; pub struct PathContext { pub home: String, pub run_user: String, } pub struct BlacklistOverlays { pub tmpfs_dirs: Vec, pub null_bind_files: Vec, } pub fn resolve_overlays(ctx: &PathContext) -> Result { let mut tmpfs_dirs: Vec = Vec::new(); let mut null_bind_files: Vec = Vec::new(); for raw in SENSITIVE_PATHS { let expanded = expand_path(raw, ctx); let mut paths = expand_glob(&expanded)?; paths.sort_by_key(|p| !p.is_dir()); for path in paths { match classify_path(&path) { PathKind::Dir(path) => { if !tmpfs_dirs.contains(&path) { tmpfs_dirs.push(path); } } PathKind::File(path) => { if !is_under_tmpfs_dir(&path, &tmpfs_dirs) && !null_bind_files.contains(&path) { null_bind_files.push(path); } } PathKind::Missing => {} } } } Ok(BlacklistOverlays { tmpfs_dirs, null_bind_files, }) } pub fn resolve_path_context() -> Result { let home = crate::require_home()?; let run_user = crate::require_run_user()?; Ok(PathContext { home, run_user }) } enum PathKind { Dir(PathBuf), File(PathBuf), Missing, } fn classify_path(path: &Path) -> PathKind { match fs::canonicalize(path) { Ok(path) if path.is_dir() => PathKind::Dir(path), Ok(path) => PathKind::File(path), Err(_) => PathKind::Missing, } } fn expand_path(raw: &str, ctx: &PathContext) -> String { let s = raw .replace("${HOME}", &ctx.home) .replace("${RUNUSER}", &ctx.run_user); let s = if let Some(rest) = s.strip_prefix('~') { format!("{}{rest}", ctx.home) } else { s }; assert!( !s.contains("${"), "unexpanded variable in SENSITIVE_PATHS entry: {raw}" ); s } fn expand_glob(pattern: &str) -> Result, SandboxError> { let entries = glob::glob(pattern)?; Ok(entries.filter_map(|r| r.ok()).collect()) } fn is_under_tmpfs_dir(path: &Path, tmpfs_dirs: &[PathBuf]) -> bool { tmpfs_dirs.iter().any(|dir| path.starts_with(dir)) } // --------------------------------------------------------------------------- // Curated sensitive paths from firejail disable-common.inc + disable-programs.inc. // Goal: protect secrets, credentials, and session tokens from agentic access. // --------------------------------------------------------------------------- const SENSITIVE_PATHS: &[&str] = &[ // -- history files (can leak passwords/tokens typed on command line) -- "${HOME}/.*_history", "${HOME}/.*_history_*", "${HOME}/.histfile", "${HOME}/.history", "${HOME}/.python-history", "${HOME}/.pythonhist", "${HOME}/.viminfo", "${HOME}/.lesshst", "${HOME}/.local/share/fish/fish_history", "${HOME}/.config/nushell/history.txt", // -- /tmp leaks -- "/tmp/xauth*", "/tmp/konsole-*.history", // -- clipboard managers (may contain copied passwords) -- "${HOME}/.cache/greenclip*", "${HOME}/.kde/share/apps/klipper", "${HOME}/.kde4/share/apps/klipper", "${HOME}/.local/share/klipper", "/tmp/clipmenu*", // -- SSH and remote access -- "${HOME}/.ssh", "${HOME}/.rhosts", "${HOME}/.shosts", "/etc/hosts.equiv", "/etc/ssh", // -- GPG -- "${HOME}/.gnupg", // -- git credentials -- "${HOME}/.git-credentials", "${HOME}/.git-credential-cache", "${HOME}/.config/hub", "${HOME}/.config/gh", // -- general credentials and secrets -- "${HOME}/.netrc", "${HOME}/.cargo/credentials", "${HOME}/.cargo/credentials.toml", "${HOME}/.fetchmailrc", "${HOME}/.msmtprc", "${HOME}/.smbcredentials", "${HOME}/.davfs2/secrets", "${HOME}/.config/msmtp", "${HOME}/.config/keybase", "${HOME}/.minisign", "${HOME}/.caff", "${HOME}/.password-store", // -- cloud provider credentials -- "${HOME}/.aws", "${HOME}/.boto", "${HOME}/.config/gcloud", "${HOME}/.kube", "${HOME}/.passwd-s3fs", "${HOME}/.s3cmd", "/etc/boto.cfg", // -- keyrings and wallets -- "${HOME}/.gnome2/keyrings", "${HOME}/.local/share/keyrings", "${HOME}/.local/share/kwalletd", "${HOME}/.kde/share/apps/kwallet", "${HOME}/.kde4/share/apps/kwallet", // -- certificates and PKI -- "${HOME}/.pki", "${HOME}/.cert", "${HOME}/.local/share/pki", "${HOME}/.local/share/plasma-vault", "${HOME}/.vaults", // -- KeePass databases -- "${HOME}/*.kdb", "${HOME}/*.kdbx", // -- encryption -- "${HOME}/.ecryptfs", "${HOME}/.fscrypt", "${HOME}/.Private", "${HOME}/Private", "/.fscrypt", "/home/.ecryptfs", "/home/.fscrypt", "/crypto_keyfile.bin", // -- system auth files -- "/etc/shadow", "/etc/shadow+", "/etc/shadow-", "/etc/gshadow", "/etc/gshadow+", "/etc/gshadow-", "/etc/passwd+", "/etc/passwd-", "/etc/group+", "/etc/group-", "/etc/sudo*.conf", "/etc/sudoers*", "/etc/doas.conf", "/etc/davfs2/secrets", "/etc/msmtprc", // -- session directory and sockets (lateral movement vectors) -- "/tmp/ssh-*", "/tmp/tmux-*", "${RUNUSER}", // -- mail (sensitive content) -- "${HOME}/.Mail", "${HOME}/.mail", "${HOME}/Mail", "${HOME}/mail", "${HOME}/postponed", "${HOME}/sent", "${HOME}/.mutt", "${HOME}/.muttrc", // -- password managers -- "${HOME}/.keepass", "${HOME}/.keepassx", "${HOME}/.keepassxc", "${HOME}/.config/KeePass", "${HOME}/.config/KeePassXCrc", "${HOME}/.config/keepassxc", "${HOME}/.cache/keepassxc", "${HOME}/.local/share/KeePass", "${HOME}/.config/1Password", "${HOME}/.config/Bitwarden", "${HOME}/.config/Enpass", "${HOME}/.cache/Enpass", "${HOME}/.local/share/Enpass", "${HOME}/.lastpass", "${HOME}/.config/Authenticator", "${HOME}/.cache/Authenticator", // -- browser profiles (saved passwords, cookies, session tokens) -- "${HOME}/.mozilla", "${HOME}/.cache/mozilla", "${HOME}/.config/mozilla", "${HOME}/.config/google-chrome", "${HOME}/.cache/google-chrome", "${HOME}/.config/chromium", "${HOME}/.cache/chromium", "${HOME}/.config/BraveSoftware", "${HOME}/.cache/BraveSoftware", "${HOME}/.config/microsoft-edge", "${HOME}/.cache/microsoft-edge", "${HOME}/.config/vivaldi", "${HOME}/.cache/vivaldi", "${HOME}/.config/opera", "${HOME}/.cache/opera", "${HOME}/.librewolf", "${HOME}/.cache/librewolf", "${HOME}/.config/qutebrowser", "${HOME}/.cache/qutebrowser", "${HOME}/.local/opt/tor-browser", "${HOME}/.tor-browser*", "${HOME}/.cache/torbrowser", "${HOME}/.config/torbrowser", // -- cryptocurrency wallets -- "${HOME}/.*coin", "${HOME}/.bitcoin", "${HOME}/.electrum*", "${HOME}/.ethereum", "${HOME}/Monero/wallets", "${HOME}/wallet.dat", // -- nyx (tor controller) -- "${HOME}/.nyx", // -- D-Bus sockets (can execute commands via systemd) -- "/run/dbus", "/var/run/dbus", // -- input devices (keylogging via evdev) -- "/dev/input/", // -- X11 / Wayland sockets (keystroke injection, screen capture) -- "/tmp/.X11-unix", "/tmp/.ICE-unix", "/tmp/.XIM-unix", "${RUNUSER}/wayland-*", "${RUNUSER}/X11-display", // -- container/VM runtime sockets (sandbox escape vectors) -- "/var/run/docker.sock", "${RUNUSER}/docker.sock", "${RUNUSER}/podman/podman.sock", "/var/run/podman/podman.sock", "${RUNUSER}/containers/", "${RUNUSER}/crun", "${RUNUSER}/libpod", "${RUNUSER}/runc", "${RUNUSER}/toolbox", "/var/run/libvirt/libvirt-sock", "/var/run/libvirt/libvirt-sock-ro", "${RUNUSER}/libvirt/libvirt-sock", // -- package manager sockets (can install/run arbitrary code) -- "${RUNUSER}/snapd-session-agent.socket", "${RUNUSER}/.flatpak*", "${RUNUSER}/.dbus-proxy", // -- window manager IPC (allows arbitrary shell execution) -- "/tmp/i3-*/ipc-socket.*", "${RUNUSER}/i3/ipc-socket.*", "/tmp/sway-ipc.*", "${RUNUSER}/sway-ipc.*", // -- database sockets (data access) -- "/var/run/mysqld/mysqld.sock", "/var/run/mysql/mysqld.sock", "/tmp/.s.PGSQL.*", ];