WeSearch

Show HN: Minimal Linux sandboxes to manage AI-Generated Code with ease

·7 min read · 0 reactions · 0 comments · 3 views
#sandboxing#rust#linux security#ai code execution#container isolation
Show HN: Minimal Linux sandboxes to manage AI-Generated Code with ease
⚡ TL;DR · AI summary

agentjail is a Rust-based library for creating minimal Linux sandboxes to securely run untrusted AI-generated code using kernel namespaces, seccomp, cgroups, and Landlock. It offers fine-grained resource controls, network isolation with optional egress allowlisting, and supports optional GPU access and a control plane with SDKs and web UI. The core sandboxing is in beta and production-use ready, while higher-level components remain pre-release. It emphasizes security through minimal attack surface, verified threat modeling, and tenant-isolated execution for multi-user environments.

Key facts
Original article
GitHub
Read full at GitHub →
Full article excerpt tap to expand

agentjail Minimal Linux sandboxes for running untrusted code. A Rust library plus optional control plane. One jail is one child process inside a fresh set of Linux namespaces, pivot-rooted into a minimal filesystem, seccomp-filtered, cgroup-limited, and optionally walled behind an egress-proxy allowlist. No VM. No daemon. No setuid helper. Status — beta. The core crate (crates/agentjail) is the load-bearing piece and is covered by a privileged test suite (make test-rust-privileged). The control plane, TypeScript/Python SDKs, web UI, and gateway are useful but not yet production-hardened. Pin a version, read the threat model, then depend on it. Isolation Namespaces — mount, network, IPC, PID; optionally user. Filesystem — pivot_root onto a bind-mounted, 128-bit-random temp root; old root is umount2(MNT_DETACH)-ed. Minimal /bin, /lib, /usr binds; tmpfs /etc with just what dynamic linking and DNS need. Landlock on Linux ≥ 5.13 (hard-fail if enabled on a kernel that lacks it). Network — None, Loopback, or Allowlist(domains). Allowlist mode routes through an in-process HTTP CONNECT proxy that resolves the hostname once, rejects private/link-local/loopback/CGNAT IPs, and connects to the resolved address (not the hostname) to close DNS rebinding. Veth pair configured via netlink; no ip binary. Syscalls — seccomp-BPF blocklist (Standard / Strict). Blocks namespace, mount, module, keyring, BPF, perf, io_uring, chroot, name_to_handle_at, ptrace, personality, clone3, mount_setattr, memfd_create, fanotify_init, quotactl, syslog; argument-filters ioctl(*, TIOCSTI, …) and socket(AF_NETLINK|AF_PACKET|AF_VSOCK, …). Privileges — PR_SET_NO_NEW_PRIVS, close_range(3, ~0, CLOEXEC) before exec, full bounding-set drop + SECBIT_NOROOT_LOCKED | SECBIT_NO_SETUID_FIXUP_LOCKED + capset zeroing every effective, permitted, and inheritable capability, in the grandchild after /proc is remounted in the new PID namespace. Resources — memory / CPU / PIDs / disk I/O via cgroup v2, gated by a barrier pipe: the child blocks until the parent has assigned the cgroup, so there is no unconstrained startup window. Requirements Linux ≥ 5.13, cgroup v2, user namespaces. Rust 1.85+ (edition 2024). CAP_NET_ADMIN — Allowlist mode only (veth + netlink). Use [dependencies] agentjail = "0.1" tokio = { version = "1", features = ["rt", "macros"] } use agentjail::{Jail, preset_build}; #[tokio::main] async fn main() -> anyhow::Result<()> { let jail = Jail::new(preset_build("./src", "./out"))?; let out = jail.run("npm", &["run", "build"]).await?; println!("exit={} oom={}", out.exit_code, out.oom_killed); Ok(()) } Presets Preset Network Memory Timeout preset_build None 512 MB 600 s preset_install Allowlist 512 MB 600 s preset_agent None 256 MB 300 s preset_gpu None 8 GB 3600 s preset_dev Loopback 1 GB 3600 s preset_install requires explicit domains: preset_install("./src", "./out", vec![ "registry.npmjs.org".into(), "registry.yarnpkg.com".into(), ]) Config use agentjail::{Jail, JailConfig, Network, SeccompLevel}; let jail = Jail::new(JailConfig { source: "/code".into(), // read-only at /workspace output: "/artifacts".into(), // read-write at /output network: Network::None, seccomp: SeccompLevel::Standard, memory_mb: 512, cpu_percent: 100, // 100 = 1 core max_pids: 64, io_read_mbps: 100, io_write_mbps: 50, timeout_secs: 300, ..Default::default() })?; Network Network::Allowlist(vec![ "api.anthropic.com".into(), "registry.npmjs.org".into(), "*.mcp.example.com".into(), ]) The proxy validates the…

This excerpt is published under fair use for community discussion. Read the full article at GitHub.

Anonymous · no account needed
Share 𝕏 Facebook Reddit LinkedIn Email

Discussion

0 comments

More from GitHub