Wrap any process in a lightweight containment layer that restricts filesystem and network access using native OS mechanisms. No containers, no VMs.
# Setup: run once to write ~/.config/pent/pent.toml.
# @claude, @npm, @gh, etc. are profiles: named sets of domains and filesystem paths.
pent config add --global @claude @gh @npm @cargo @pip @gem @go @git
# Run: every invocation. Pent enforces the config:
# only listed domains resolve, only listed paths are accessible.
pent run -- claude
# Inspect what's allowed
pent config showPent is for developers who need to run powerful but untrusted processes without giving them unrestricted access to the filesystem and network.
| Pent | Docker | Firejail | bubblewrap | |
|---|---|---|---|---|
| Target | Any process | Services & apps | Desktop apps | Any process |
| Platforms | macOS & Linux | All (via VM) | Linux only | Linux only |
| Network control | Domain allowlist | IP/port rules | IP/firewall | None |
| Filesystem control | Path allowlist + overlayfs | Volume mounts | Path rules | Bind mounts |
| Setup | Zero-config profiles | Dockerfile | Per-app profiles | Manual flags |
| Overhead | Native (no VM) | High | Low | Low |
Pent launches a child process inside a sandbox with two complementary controls.
Filesystem isolation restricts the child to only the paths you explicitly allow. On Linux, directories containing writable files are additionally shadowed with overlayfs so that non-allowlisted sibling files are hidden and writes to them are discarded when the session ends.
Network isolation gates the child's outbound traffic through a built-in proxy that enforces a domain allowlist.
Pent is not a security tool. It is designed to catch accidental misbehaviour, not to stop a determined adversary. Use Pent to add a reasonable guard-rail around untrusted processes operating on your workstation, not as a substitute for proper network segmentation.
On macOS, Pent generates a Sandbox Profile Language (SBPL) policy and launches the child process via sandbox-exec.
Network containment is not yet available on macOS. macOS does not expose network namespaces or a programmable packet filter API accessible without root, so the veth+proxy approach used on Linux has no direct equivalent. See Platform limitations below.
On Linux, Pent combines three kernel mechanisms. Landlock LSM restricts filesystem access at the kernel level. Overlayfs shadowing protects parent directories by mounting a temporary layer in a private namespace; writes to non-allowlisted paths disappear when the process exits. Network namespaces (unshare(CLONE_NEWNET)) isolate the network stack, with traffic bridged to Pent's proxy via a veth pair.
Pent includes a DNS and TCP proxy. The DNS side returns NXDOMAIN for disallowed domains. The TCP side only forwards connections when the destination IP resolves to an allowed domain.
--allow and --network proxy are accepted on macOS but do not yet enforce network policy. Pent runs with unrestricted network access until a macOS-compatible isolation mechanism is implemented. On Linux, network policy is enforced at the kernel level via network namespaces.
brew tap valentinradu/pent
brew install pentyay -S pentcurl -fsSL https://valentinradu.github.io/Pent/apt/KEY.gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/pent.gpg
echo "deb [signed-by=/etc/apt/keyrings/pent.gpg arch=$(dpkg --print-architecture)] \
https://valentinradu.github.io/Pent/apt ./" \
| sudo tee /etc/apt/sources.list.d/pent.list
sudo apt update
sudo apt install pent# Restricted network (domain allowlist)
pent run --allow example.com -- curl https://example.com
# No network access
pent run --network blocked -- curl https://example.com
# Read-only access to specific paths
pent run --read /etc/ssl/certs -- my-app# Add profiles for common tools
pent config add --global @claude @gh @npm
# Run the tool (config is applied automatically)
pent run -- claudeUse --trace to log every denial without killing the process. Pent will emit a fix hint for each violation so you can copy-paste the missing paths and domains into your config.
pent run --trace -- claude
cat .pent/trace.logExample output:
pent: [denied] filesystem: "claude" was denied "read" access to "/Users/alice/.ssh/id_rsa"
pent: fix: add "/Users/alice/.ssh/id_rsa" to [sandbox.paths.read] in your pent config
--trace only records accesses that Pent's sandbox actually intercepts and denies. It cannot tell you everything a binary will try to open before you run it. For a complete picture, use strace.
strace intercepts every system call the process makes, including all file opens. This lets you build a complete allowlist before running under Pent.
strace -e trace=openat,open,stat,statx,access,faccessat \
-f -o strace.log \
your-commandTo extract the paths it tried to open, run grep -oP '"\K[^"]+(?=", O_)' strace.log | sort -u for successful opens and grep 'EACCES\|ENOENT' strace.log | grep -oP '"\K[^"]+(?=")' | sort -u for denials. Then add the relevant entries to your Pent config:
[sandbox.paths]
read = ["/path/to/thing"]
write = ["/path/to/writable"]Profiles are the heart of Pent's zero-config experience. If you use a tool that isn't covered, please contribute a profile by opening crates/pent-settings/src/profiles.rs, adding your tool to the Profile enum and PROFILES table, defining its domains and paths in profile_config, and submitting a PR.
MIT, see LICENSE.