v2.0.0
ai-jail 2.0 is the "control and visibility" release: filtered egress, a
launch audit log, and credential-file hygiene. Fully backward-compatible —
every v1.x config keeps working unchanged; everything below is opt-in.
Added
-
Filtered egress:
--allow-host/allow_hosts. Between "no network"
and "all network" there is now a third mode: the sandbox can reach exactly
the hosts you allow, over TCP, via CONNECT — and nothing else.
ai-jail --allow-host api.anthropic.com --allow-host github.com claude.
Entries match the host and its subdomains; private, loopback, link-local,
CGNAT, multicast, and cloud-metadata addresses are refused after DNS
resolution (which happens once — the checked answer is the one dialed, so
DNS rebinding gets nothing).Enforcement is kernel-level, not a polite suggestion: on Linux the sandbox
keeps its private network namespace with no external route at all, and a
tiny in-sandbox bridge (spawned before Landlock/seccomp apply, so it alone
stays unrestricted) forwards loopback TCP to the proxy over a bind-mounted
Unix socket; on macOS the seatbelt profile allows outbound only to
localhost:<proxy-port>. The proxy itself is ~400 auditable std-only
lines — no TLS termination, no CA, no new dependencies. Proxy-unaware
processes that ignorehttp_proxysimply fail, which is the safe
direction. Honest caveats (in README and docs/SECURITY.md): an allowed
host is trusted wholesale, and on macOS the system resolver is not fenced.
Design and rationale: docs/connect-proxy-plan.md and
docs/openshell-comparison.md. -
Launch audit log:
--audit-log/audit_log = true. Appends one
JSONL record per launch (command, effective capabilities, config sources,
exit code, duration) to~/.local/share/ai-jail/history.jsonl(0700 dir,
0600 file, symlinks refused). With filtered egress active, the proxy also
records every CONNECT allow/deny verdict — "what did the agent try to
reach?" is now answerable. Off by default; a project.ai-jailcan
disable but never enable it. -
--env-from-file PATH. ReadsKEY=VALUElines from a strictly
validated file (user-owned, mode 0600, not a symlink, outside the
project) and injects them like--env, with--envwinning conflicts.
Never persisted to any config file; project.ai-jailcannot set it.
This codifies the credential pattern: secrets live in the host
environment or a 0600 file, never in an.ai-jailfile. -
Launch warnings learned filtered mode. Known API clients no longer
warn about network when filtered egress covers their API host — and do
warn, naming the host, when it doesn't.
Fixed
- Filtered egress +
--lockdownno longer deadlocks the allowlist on
kernels ≥ 6.7: lockdown's Landlock V4 ruleset now allows ConnectTcp to
the in-sandbox bridge port (safe — inside the private netns that port is
loopback-only), everything else stays denied. - The proxy's SSRF guard also refuses multicast and deprecated
v4-compatible IPv6 addresses.
Changed
--allow-tcp-portremains disabled (UDP cannot be isolated); its error
now points at--allow-host, which supersedes it. The Landlock V4 port
machinery stays for lockdown.
Checksums (SHA256)
f3af60744ba2a57f6b46568a16cdbe1c625c30f9bf99f1e5099f695849963113 ai-jail-linux-x86_64.tar.gz
98f3edddb312d74cc32a8c51367a28fbc27e8bec9574ed2a45d6825fd92aaabf ai-jail-macos-aarch64.tar.gz
Install
brew tap akitaonrails/tap && brew install ai-jail
yay -S ai-jail-bin
cargo install --locked ai-jail