Sandboxing Overview
Scarab-Runtime uses five independent, kernel-enforced isolation mechanisms to sandbox every agent. The combination provides defense in depth: a bypass of one layer does not compromise the others.
Five Enforcement Layers
| Layer | Mechanism | What It Enforces |
|---|---|---|
| 1 | Tool dispatch (userspace) | Capability tokens before every tool call |
| 2 | seccomp-BPF | Per-agent syscall allowlist |
| 3 | AppArmor | Per-agent MAC profile (files, network) |
| 4 | cgroups v2 | Per-agent resource limits (memory, CPU, open files) |
| 5 | nftables | Per-agent network policy |
| + | Linux namespaces | Process, network, and mount isolation |
Profile Generation
All kernel profiles are derived automatically from the agent's manifest at spawn time. The profile_gen.rs module reads the manifest and produces:
- A seccomp-BPF filter: syscalls are allowed based on the agent's trust level and declared capabilities
- An AppArmor profile: file path rules derived from
fs.read,fs.writecapabilities; network rules fromspec.network - cgroup limits: memory and cpu.shares from
spec.resources - nftables rules: derived from
spec.network.policyandspec.network.allowlist
An agent cannot modify its own profiles. Profile modification requires daemon-level access.
PlatformEnforcer
The PlatformEnforcer trait is the abstraction over Linux enforcement. The default implementation:
- Uses
seccompcrate for BPF filter application - Uses AppArmor via the kernel's
AA_SETPROFinterface - Uses cgroups v2 via
/sys/fs/cgroup/ - Uses nftables via the
nftcommand or netlink - Uses
clone()withCLONE_NEWPID,CLONE_NEWNET,CLONE_NEWNSfor namespaces
A MockPlatformEnforcer is used in tests to avoid requiring root.
Universal Sandbox Guarantee
Every agent runs in a sandbox, regardless of trust level. A privileged agent is privileged within the agent world (it can access a wider set of capabilities), but:
- It cannot write to
/usr,/lib,/bin,/boot - It cannot modify kernel parameters
- It cannot access other agents' workspaces
- It cannot read secrets it hasn't declared
The agentd process itself is the trusted root. It applies profiles to all agents and is not subject to agent-level enforcement.
Coverage Diagram
Each layer covers attack surfaces the others cannot reach. The diagram below maps every layer to the threats it uniquely addresses.
| Threat | Tool dispatch | seccomp-BPF | AppArmor | cgroups v2 | nftables | Namespaces |
|---|---|---|---|---|---|---|
Capability not declared (fs.write, net.*) | ✓ | |||||
Dangerous syscall (ptrace, kexec, pivot_root) | ✓ | |||||
Memory exfiltration (process_vm_readv/writev) | ✓ | |||||
| Kernel escape via new user namespace | ✓ | |||||
| Filesystem path access outside capability scope | ✓ | |||||
Host system path writes (/bin, /lib, /boot) | ✓ | |||||
| Exec of arbitrary binary | ✓ | |||||
| Memory exhaustion / CPU starvation | ✓ | |||||
| Fork bomb / PID exhaustion | ✓ | |||||
| Unauthorized network destination (IP/port) | ✓ | |||||
| Data exfiltration to non-allowlisted host | ✓ | |||||
| Seeing other agents' PIDs / sending signals | ✓ | |||||
/proc enumeration of other agents | ✓ | |||||
| Agent seeing host mounts or other workspaces | ✓ |
✓ = the sole layer enforcing this restriction
Why each layer is necessary
Tool dispatch (userspace) is the only layer that understands Scarab capability tokens. It rejects calls like fs.write before any kernel involvement, and is the enforcement point for HITL approvals, anomaly detection, and audit logging. The kernel layers below it have no concept of capability tokens.
seccomp-BPF is the only layer that can block specific syscalls and their arguments at kernel entry. AppArmor cannot deny ptrace(2), process_vm_readv(2), kexec_load(2), or clone(CLONE_NEWUSER), as these primitives operate below the VFS and network layers that AppArmor models. seccomp stops them before they reach the kernel proper.
AppArmor (MAC) is the only layer that enforces access control at the filesystem inode level, independent of the process's own capabilities or file descriptors. An agent that obtains a raw file descriptor through a syscall that seccomp allows will still be denied by AppArmor if the path is outside its profile. AppArmor also controls which binaries the agent may exec, which seccomp cannot express at the path level.
cgroups v2 is the only layer that limits resource consumption. No other layer can prevent a process from allocating all available memory, spinning all CPUs, or exhausting file descriptors. Without cgroups, a single agent could degrade or crash all other agents on the host.
nftables is the only layer that enforces network policy at the packet level inside the agent's network namespace. AppArmor's network inet rules control whether a socket can be created, but cannot restrict destination IP addresses or ports. nftables enforces the allowlist at the packet level, independent of the agent binary.
Namespaces are the only layer that provides isolation by partition rather than by denial. They ensure each agent has a private PID space, private network stack, and private mount tree. Without namespaces, a process confined by AppArmor and seccomp could still read /proc/<other-agent-pid>/fd or observe host mount points, as these are legal syscalls and legal paths in a flat process model.
Validation Tests
Enforcement tests run under sudo cargo test and validate that the enforcement actually works on real hardware. These tests:
- Verify that cgroup memory limits are applied and enforced
- Verify that seccomp-BPF denies disallowed syscalls
- Verify that AppArmor profiles block unauthorized file access
- Verify that nftables rules block unauthorized network connections