Home
Why Sandlock
How It Works Use Cases Comparison Security Model
Docs
Documentation Home Getting Started CLI Reference Python SDK Sandbox Reference FAQ
Products
Overview Sandbox HTTP API Sandbox Scheduler
GitHub Schedule a Demo
Architecture

How Sandlock Works

Not a runtime the workload runs inside: a policy the kernel applies to a process between fork() and exec(), so it never executes an unconfined instruction.

By Cong Wang · Updated

Three mechanisms

What Enforces What

As much policy as possible goes into the kernel. Only rules it cannot express, such as a destination IP or an HTTP path, reach the supervisor.

Layer 1

Landlock

Kernel

Linux's unprivileged access-control LSM. The policy's filesystem, network, and IPC rules become a Landlock ruleset applied to the child; the kernel evaluates every access against it, and it can never be relaxed for the life of the process tree. It costs nothing per syscall beyond the kernel's own check.

  • Filesystem. Recursive PATH_BENEATH rules, resolved by the kernel at access time, so immune to TOCTOU races.
  • TCP. Connect and bind port allowlists (ABI v4).
  • IPC. Abstract UNIX socket and signal scoping (ABI v6).
Layer 2

seccomp-bpf

Kernel

A filter removes syscall families a confined workload has no legitimate use for. The default blocklist is always applied; a policy can add denials or re-enable named groups such as System V IPC. Installed with NO_NEW_PRIVS and inherited by every descendant, the same filter also carries the notification listener for layer 3.

A no-supervisor mode uses layers 1 and 2 alone, which is how one sandlock nests inside another.

Layer 3

seccomp user notification

Supervisor

"Connect only to this IP", "stop at 512 MB", "stage this write" all need a decision at the moment the syscall happens. Seccomp user notification hands those syscalls to an async supervisor in the parent. Its responsibilities are narrow and its ordering fixed: built-in handlers run first, custom ones after, so a handler can extend confinement but never subvert it.

Startup

The Confinement Sequence

Every restriction is in place before the workload's first instruction, and the parent supervises only after the child confirms the filter is installed.

In the child, after fork()
  1. 1setpgid(0,0)
  2. 2chdir(cwd), if the policy sets one
  3. 3NO_NEW_PRIVSa setuid binary can now confer nothing
  4. 4Landlock ruleset appliedfilesystem, network, and IPC
  5. 5seccomp filter installeddeny list plus the notification listener, whose descriptor goes to the parent
  6. 6Wait for the parent's ready signal
  7. 7Close every descriptor above stderr
  8. 8exec(cmd)the workload's first instruction, already confined
In the parent, meanwhile
  • Receives the notification descriptor
  • Starts the supervisor on tokio
  • Patches the vDSO, if time is frozen
  • Starts the policy callback thread, if one is set
  • Starts the CPU throttle task, if one is set

Everything on the left happens before the workload exists. Everything on the right supervises it once it does.

Why fds are closed at step 7. A descriptor inherited from the parent was opened before confinement, so the kernel honours it. Closing everything above stderr removes that escape hatch.

The supervisor

Which Syscalls Take a Round Trip

Only these syscalls are intercepted, and only when the matching policy feature is active. Everything else runs at full speed.

Syscall What the supervisor does
clone / fork / vforkEnforces the concurrent process count
mmap / munmap / brk / mremapTracks the memory limit
connect / sendto / sendmsgDestination IP allowlist, on-behalf execution, HTTP ACL redirect
bindOn-behalf bind and port remapping
openat/proc virtualization and COW interception
unlinkat / mkdirat / renameat2COW write interception
execve / execveatPolicy callback hold and vDSO re-patching
getrandomDeterministic PRNG injection
clock_nanosleep / timer_settimeTimer adjustment when time is frozen
getdents64PID filtering and COW directory merging
getsocknamePort remap translation
Network enforcement

Two Paths, Chosen by Your Policy

Sandlock picks the cheapest path that can express your rules. Nothing to configure; it falls out of the policy.

Direct path

For pure TCP port rules with no host, IP, CIDR, or HTTP ACL. Landlock enforces the allowlist in the kernel; no per-syscall overhead.

Zero userspace round trips
Example: --net-allow :443

On-behalf path

For any host, IP, CIDR, UDP, ICMP, or HTTP rule, since the destination must be inspected. The supervisor duplicates the child's socket, checks the destination, and performs the syscall itself.

Per-connection check, not per-packet
Example: --net-allow api.example.com:443
Components

One Core, Many Front Ends

One Rust core. Every interface drives it through the same policy object.

Interfaces
sandlock CLI Python SDKctypes Go SDKcgo sandlock-ociOCI runtime
C ABI
libsandlock_ffi.so
Core
sandlock-coreLandlock · seccomp · COW · pipeline · policy_fn · vDSO

The CLI and SDKs go through the C ABI. sandlock-oci links the core directly, being a Rust crate itself.

Component Role
sandlock-coreRust library: Landlock, seccomp, supervisor, COW, pipelines
sandlock-cliThe sandlock binary
sandlock-ociOCI runtime shim for containerd, CRI-O, and Kubernetes
sandlock-ffiC ABI shared library, libsandlock_ffi.so
Python SDKctypes bindings over the FFI library, plus an MCP server
Go SDKcgo bindings over the FFI library
Research

The Paper Behind the Design

This architecture is described in full, with measurements, in the paper and the engineering posts.

Paper

Sandlock: Confining AI Agent Code with Unprivileged Linux Primitives

Cong Wang and Yusheng Zheng. arXiv:2605.26298, May 2026.

“Sandlock is a lightweight Linux process sandbox organized around a simple split: static, input-independent policy is compiled into kernel-enforced rules, while a narrow supervisor handles runtime-dependent decisions and virtualized effects. This split lets Sandlock enforce filesystem, network, IPC, and syscall policies without root, cgroups, images, or mandatory namespaces.”
Requirements

What the Host Kernel Must Provide

Linux 6.12 or later, where Landlock ABI v6 lands. Individual protections can be waived per policy for a mixed fleet.

Capability Minimum kernel
seccomp user notification5.6
Landlock filesystem rules5.13
Landlock TCP port rules (ABI v4)6.7
Landlock IPC scoping (ABI v6)6.12

sandlock check reports the kernel's Landlock ABI and available protections. Building needs Rust 1.70; the Python SDK needs Python 3.8.

Read the Documentation

Every field, flag, and enforcement rule, from a five-minute quickstart to the full reference.