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

What Sandlock Guarantees, and What It Does Not

A sandbox is only useful if you know its edges. This page states the trust boundaries, the guarantees each layer provides, and the attacks that are explicitly out of scope.

Trust boundaries

Three Tiers of Trust

Sandlock's design principle is that the amount of trust placed in userspace should be as small as the policy allows.

Fully trusted

The host kernel

Landlock rules and the seccomp-bpf filter are evaluated by the kernel. If the kernel is compromised, so is every guarantee on this page. Sandlock shares a kernel with its workload, and that is the fundamental limit of the model.

Partially trusted

The supervisor

Runs in the parent process, outside the sandbox. It decides on the syscalls the kernel hands it: destination IPs, resource accounting, COW writes. Its handler chain is fixed, with built-ins first, so a custom handler can extend confinement but never relax it.

Untrusted

The workload

Assumed hostile. It never executes an unconfined instruction: NO_NEW_PRIVS, Landlock, and the seccomp filter are all installed before exec, and inherited descriptors above stderr are closed first.

Scope

In Scope and Out of Scope

Sandlock defends against

  • Filesystem escape. Only paths reachable through the granted Landlock rules can be opened. Grants are recursive and denials override them.
  • Unapproved network egress. Default-deny. With no rules Landlock refuses every TCP connect, and UDP, ICMP, and raw socket creation are refused at the seccomp layer.
  • Exfiltration on an approved host. HTTP rules match method, host, and path, so an agent allowed one endpoint cannot repurpose the connection.
  • Credential theft by the workload. The secret stays in the supervisor and is attached after the ACL check; an env: source is stripped from the child.
  • Privilege escalation via setuid. NO_NEW_PRIVS is set before the filter, so a setuid binary confers nothing.
  • Reaching sibling processes. Landlock ABI v6 scopes deny abstract UNIX socket connections and signals outside the sandbox.
  • Host resource exhaustion. Memory, concurrent processes, open files, CPU share, and COW disk usage are all capped.
  • Unintended writes. Copy-on-write stages writes and discards them on error, so a failed run leaves the tree untouched.

Sandlock does not defend against

  • Kernel vulnerabilities. The workload runs on your kernel. An escalation bug in a permitted syscall defeats the sandbox. This is the price of no hypervisor.
  • Hardware side channels. Spectre-class attacks and cache timing are out of scope. CPU pinning reduces sharing but is not a mitigation.
  • A policy that grants too much. --net-allow '*' permits any destination. Sandlock enforces the policy you wrote, not the one you meant.
  • A hostile launcher. An attacker who already controls the process that starts Sandlock controls the policy.
  • The workload starving itself. Limits protect the host, not the workload's own progress. A sandbox can still spin or wedge inside its budget.
  • Open-file limits as a boundary. RLIMIT_NOFILE can be raised again by a sandbox launched with the privilege to do so. Treat it as a budget.
  • Covert channels between sandboxes. Two sandboxes on one host share timing, disk, and memory bandwidth.
  • Packet crafting. Raw ICMP sockets are never exposed. A deliberate reduction in capability, not an oversight.
Design detail

Time-of-Check to Time-of-Use

Seccomp user notification has a well-known hazard, documented in seccomp_unotify(2): after the supervisor returns a continue verdict, the kernel re-reads any argument the syscall passed by pointer. A supervisor that inspects a path string and then allows the call has validated a string the workload is free to overwrite in the interval. Filtering on path strings in userspace is therefore unsound, no matter how carefully it is written.

Sandlock addresses this in two ways rather than papering over it.

Path strings are never exposed to policy callbacks

Policy events carry the syscall name, category, PID, network destination, and argv, but never a path. Path-based access control belongs in static Landlock rules, where the kernel resolves the path itself at access time and no window exists. For decisions that genuinely have to be made at runtime, the policy context offers deny_path() and allow_path(), which add Landlock-side restrictions rather than filtering strings.

argv is exposed, and it is made safe first

Command lines are too useful to withhold, so Sandlock makes them safe instead. Before exposing argv for an execve, the supervisor freezes every task in its process index, including peer processes that could alias the argv memory through a shared mapping. While a policy callback is active, fork-like syscalls are traced for one creation event so that children are registered before they can run user code.

If the freeze or the creation tracking cannot be established, for instance because a YAMA policy blocks ptrace, the syscall is denied with EPERM. The safety invariant is never silently relaxed in favour of letting the workload proceed.

Defaults

Strict by Default, Explicit to Weaken

Sandlock starts from deny and requires you to open things up. This matters because the failure mode of a permissive default is silent: nothing breaks, and you learn about the gap from an incident rather than from an error.

Surface With no policy To open it up
Filesystem Nothing readable or writable. No implicit grant for /usr or /lib. Name every path, which is why every example on this site does.
Network Landlock denies every TCP connect; UDP, ICMP, and raw socket creation are denied at the seccomp layer. --net-allow '*' explicitly. ICMP still needs its own icmp:// rule on top.
Syscalls The default blocklist applies unconditionally and cannot be turned off. Named groups only, such as System V IPC. An unknown group name is rejected, so a typo fails loudly.
Kernel protections Every protection the host supports is enforced, and Sandlock refuses to start when one it expects is missing. Per protection, explicitly: allow_degraded skips it where the kernel lacks it, disable turns it off outright.

Protocol availability follows rule presence: with no UDP rule, UDP sockets cannot be created at all. A sandbox's resolved protection posture is part of its checkpoint, so a restored sandbox returns with the protections it was built with rather than whatever the new host offers. sandlock check reports the host's Landlock ABI before you deploy.

Secrets

Credential Handling

A workload can use a secret without ever holding it. The value is loaded into the supervisor from an environment variable, a file, or a file descriptor, and attached to a matching request inside the proxy strictly after the ACL check has passed, so a request the policy would reject never carries it.

  • The child never carries the value. An env: source is stripped from the child's environment, so a compromised agent cannot read its own key back. An fd: source never touches disk.
  • Cleartext HTTP warns rather than failing silently. Attaching a credential over plain HTTP sends it upstream in the clear, so Sandlock emits a one-per-run warning instead of treating the transport as safe.
  • The MITM CA's private key stays in memory. --http-inject-ca generates an ephemeral CA, writes only the public certificate into the trust bundles you name, and never persists the key.

Sandlock ships no secret-manager client, deliberately. An external fetcher materializes the value into a file: or fd: source, keeping it off ps, out of shell history, and out of the child's environment, and letting you use Vault, a cloud secret store, or a CSI driver without Sandlock having an opinion.

Disclosure

Reporting a Vulnerability

If you believe you have found a way to escape a Sandlock policy, we want to hear about it before anyone else does.

Email contact@multikernel.io with a description and, where possible, a reproducer. Please do not open a public issue for a suspected escape until we have had a chance to respond.