Skip to content

valentinradu/Pent

Repository files navigation

Pent

License: MIT Platform: Linux | macOS

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 show

Why Pent?

Pent 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

What Pent does

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.

Security disclaimer

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.

How it works

macOS: Seatbelt (sandbox-exec + SBPL)

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.

Linux: Landlock + overlayfs + network namespaces

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.

Built-in proxy

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.

Platform limitations

macOS: network containment not yet available

--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.

Installation

Homebrew (macOS / Linux)

brew tap valentinradu/pent
brew install pent

AUR (Arch Linux)

yay -S pent

Debian / Ubuntu

curl -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

Quick start

One-off runs

# 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

Persistent configuration

# Add profiles for common tools
pent config add --global @claude @gh @npm

# Run the tool (config is applied automatically)
pent run -- claude

Debugging

--trace: log policy violations at runtime

Use --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.log

Example 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: discover all filesystem access upfront

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-command

To 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"]

Contributing profiles

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.

License

MIT, see LICENSE.

About

Run any untrusted process with restricted filesystem and network access, using native OS primitives.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Languages