Security Model
jai is a casual sandbox. This page explains what it protects, what it does not, and where its boundaries are. Read this before deciding whether jai is sufficient for your use case.
Integrity vs confidentiality
jai's security story is built around two distinct properties:
- Integrity — Can the jailed process destroy or modify files it shouldn't? jai's overlay and mount isolation address this.
- Confidentiality — Can the jailed process read files it shouldn't? This depends entirely on the mode.
Casual mode primarily provides integrity. Strict mode provides both integrity and confidentiality. Bare mode provides integrity with weak confidentiality.
Casual mode
Casual mode mounts your home directory as a copy-on-write overlay. Writes go to $HOME/.jai/<name>.changes and do not modify originals. The current working directory is writable. /tmp and /var/tmp are private. The rest of the filesystem is read-only.
What it protects against:
- Accidental or runaway deletion of files outside granted directories
- Rogue
rm -rf ~or similar destructive commands - Agents modifying config files, dotfiles, or data in your home directory
What it does not protect:
- Confidentiality. The process runs as your user and can read anything you can read — SSH keys, API tokens, browser data, credential files. The
--maskoption and default blacklists hide some sensitive dotfiles, but casual mode exposes everything readable by default. You cannot enumerate and mask every sensitive file. - Granted directories. The current working directory (and any
-ddirectories) have full read/write access. A jailed process can destroy everything in those directories. - Network access. jai does not restrict network access. A jailed process can exfiltrate data, make API calls, or connect to remote services.
Strict mode
Strict mode runs the jailed process as the unprivileged jai system user with an empty private home directory. Granted directories are exposed through id-mapped mounts.
What it adds over casual mode:
- UID-based confidentiality. Because the process runs as a different user, it cannot read files that are only accessible to your UID. This blocks access to most of the sensitive data in your home directory.
- Empty home directory. No dotfiles, no cached credentials, no browser profiles — the jailed process starts clean.
What it still does not protect:
- World-readable files. Files with permissions like
644outside your home directory are still readable (e.g.,/etc/passwd, system configs). This is inherent to UID-based isolation without a full container. - Granted directories. As with casual mode, directories you grant via
-dare fully read/write. - Network access. No network restrictions.
Bare mode
Bare mode uses an empty private home directory but runs as your user. It exists primarily as a fallback for NFS home directories, where id-mapped mounts are not supported.
Compared to strict mode:
- Same empty home directory
- Same private
/tmpand/var/tmp - But the process runs as your UID, so it can read any file accessible to you outside the home directory
- No confidentiality benefit beyond hiding the home directory contents
Use bare mode only when strict mode is not available due to NFS constraints.
PID namespace
All three modes use a private PID namespace (via CLONE_NEWPID). This means:
- Jailed processes cannot
killor send signals to processes outside the jail - Jailed processes cannot
ptraceprocesses outside the jail psinside the jail only shows jailed processes
This is a meaningful defense against a rogue process trying to interfere with your other running programs.
File masking
The --mask option creates overlay "whiteout" files to hide specific paths in your home directory from a casual jail. The default .defaults file masks common sensitive dotfiles like .ssh and .gnupg.
Limitations:
- Masks are only applied when the overlay mount is first created. If you add new
maskdirectives, runjai -ufirst. --unmaskonly reverses a previous--maskin the same config chain — it cannot unmask files already masked in an existing overlay.- If you mask a parent directory,
--unmaskon a child path has no effect. - In casual mode, masking is defense-in-depth, not a guarantee. Because the process runs as your user, it may be able to read the underlying files through other paths if the overlay is misconfigured.
Overlayfs caveats
- The overlay work directory (
$HOME/.jai/*.work) occasionally accumulates root-owned files that the user cannot delete. Runjai -uto clean these up. - If extended attributes on the
changesdirectory get out of sync, the overlay may fail to mount. Creating a freshchangesdirectory can resolve this. - Overlayfs requires extended attribute support. NFS does not support extended attributes, so casual mode overlays do not work on NFS home directories (use
--storageto point to a local filesystem).
NFS limitations
NFS home directories cannot use:
- Strict mode — id-mapped mounts are not supported on NFS
- Casual mode overlays — overlayfs requires extended attributes
On NFS, use --storage=/local/path to move overlay state to a local disk for casual mode, or use bare mode if you need an empty home.
Environment variable filtering
jai filters environment variables matching patterns like *_TOKEN, *_KEY, *_PASSWORD, etc. from the jailed environment. The default .defaults file sets these patterns. You can add more with --unsetenv or selectively re-expose variables with --setenv.
This is a best-effort measure. Environment variable filtering cannot catch every secret — programs may store credentials in files, keyrings, or other locations.
What jai is not
jai is not:
- A hardened container runtime (like Docker with seccomp and AppArmor profiles)
- A virtual machine
- A replacement for
gVisor,Kata Containers, or other strong isolation tools - A multi-tenant isolation boundary
- A defense against a determined adversary with local access
When to use a real container or VM
Use a proper container or VM when:
- You are running untrusted code from unknown sources (not just AI agents you chose to install)
- You need strong multi-tenant isolation between users or workloads
- You need network-level isolation (jai does not restrict network access)
- You need syscall filtering (seccomp) or mandatory access control (AppArmor, SELinux)
- The consequences of a sandbox escape are severe (production data, financial systems, medical records)
jai is designed for a different situation: you have a tool you broadly trust but want to limit the damage from bugs, mistakes, and overly eager file operations. It makes the common case safer without the overhead of a full container or VM.