Application-layer sandboxes for AI agents keep failing in production. OpenAI's German Wiki containment breach and recent 0-click RCE vulnerabilities in coding agents exposed the limits of userspace isolation. Nono moves the security boundary down to the kernel, treating agent runtime security as an OS problem rather than a framework problem.
The Isolation Gap
Most agent sandboxes rely on language runtimes, Docker namespaces, or WASM. These work until an agent discovers a prompt injection vector that bypasses the application layer. The attack surface includes:
- Tool invocation arguments that escape shell quoting
- File path traversal through symbolic links
- Network access via DNS rebinding or SSRF
- Credential leakage through environment variables or process memory
Kernel-enforced boundaries shift the trust anchor. Instead of asking "did the framework validate this correctly?" you ask "did the syscall get blocked?"
Ephemeral Micro Toolboxes
Nono creates a fresh sandbox for every tool invocation. When an agent calls gh issue view, the supervisor:
- Resolves and verifies the executable (Sigstore supply chain integrity)
- Evaluates argv policy for the caller and arguments
- Creates an invocation-scoped micro sandbox with bounded capabilities
- Injects a phantom credential token (real token stays with supervisor)
- Destroys the sandbox when the invocation exits
The sandbox sees:
- Read-only workspace (no filesystem writes)
- No host secrets
- Bounded stdout and stderr
- Network access only through the nono proxy
The proxy validates the phantom token, evaluates HTTP method and path policy, injects the real credential at the boundary, and forwards over TLS. If an action falls outside policy, the engine can route it to human approval.
Kernel Primitives in Play
Nono uses OS-level enforcement mechanisms that sit below the application layer:
seccomp-bpf: Syscall filtering at the kernel boundary. An agent tool that tries to open a file outside its allowed set gets EPERM before userspace sees the request.
LSM hooks: Linux Security Module hooks intercept operations like file access, network binding, and capability checks. Policy decisions happen in kernel space.
Namespaces: PID, mount, network, and user namespaces isolate the tool's view of system resources. The tool sees a private filesystem tree and network stack.
Atomic snapshots: Filesystem state is snapshotted before each invocation. Rollback is a pointer swap, not a diff replay.
| Isolation Layer | Bypass Vector | Nono Mitigation |
|---|---|---|
| Language runtime | Prompt injection to native code | Kernel syscall filter blocks unauthorized calls |
| Docker namespace | Shared kernel, privileged containers | seccomp-bpf + LSM hooks enforce irrevocable allow-lists |
| WASM sandbox | Host function imports, WASI escape | No shared address space; supervisor mediates all I/O |
| Application policy | Logic bugs, race conditions | Kernel enforces policy; userspace cannot override |
Credential Injection Architecture
Secrets never enter the sandbox. The supervisor holds real credentials and the sandbox receives a phantom token. When the tool makes an HTTP request:
- Proxy receives request with phantom token
- Proxy validates token against invocation context
- Proxy evaluates HTTP method and path against policy
- Proxy injects real credential at boundary
- Proxy forwards request over TLS
This prevents credential leakage through:
- Environment variable dumps
- Process memory inspection
- Stdout/stderr logging
- Core dumps or crash reports
Audit Trail and Provenance
Every security-relevant event is hash-chained into an audit record sealed with a SHA-256 Merkle root. The log captures:
- Tool invocation with argv and environment
- Policy evaluation decisions (allow, deny, human approval)
- Network requests with method, path, and response status
- Filesystem operations (read, write, stat)
- Sandbox lifecycle (create, destroy, rollback)
Sigstore integration provides supply chain integrity. The supervisor verifies executable signatures before creating the sandbox, ensuring the tool binary matches the expected artifact.
Performance and Deployment Shape
Kernel-enforced boundaries add overhead. Creating a fresh namespace and applying seccomp filters takes microseconds, but the cost accumulates across thousands of tool invocations. The trade-off:
- Latency: 100-500μs per invocation (namespace creation + seccomp setup)
- Throughput: Bounded by syscall filtering overhead, not sandbox count
- Memory: Each micro toolbox holds minimal state; destroyed on exit
For multi-tenant agent hosting, the economics shift. You can pack more isolated agents onto a single host because kernel enforcement prevents cross-tenant leakage without requiring separate VMs.
Deployment options:
- Single-host: Install via curl, Homebrew, or package manager
- Kubernetes: DaemonSet with privileged containers for LSM hook access
- Serverless: Not viable; requires kernel module or LSM support
Failure Modes
Kernel-enforced boundaries fail differently than application sandboxes:
Policy misconfiguration: An overly restrictive seccomp filter blocks legitimate syscalls. The tool fails with EPERM and the agent sees an opaque error. Debugging requires inspecting the audit log to identify the blocked syscall.
Kernel version skew: LSM hooks and seccomp features vary across kernel versions. A policy that works on 5.15 may fail on 4.19. The supervisor must detect kernel capabilities at runtime.
Phantom token leakage: If the proxy has a bug, the phantom token could be logged or leaked. The blast radius is limited to a single invocation, but the agent could replay the token.
Human approval timeout: If a tool requires human approval and the human doesn't respond, the invocation blocks. The agent needs a timeout and fallback strategy.
Code Example: Seccomp Policy
Here's a simplified seccomp-bpf filter that allows only read, write, and exit syscalls:
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <sys/prctl.h>
struct sock_filter filter[] = {
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_read, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_write, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_exit, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),
};
struct sock_fprog prog = {
.len = sizeof(filter) / sizeof(filter[0]),
.filter = filter,
};
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
Nono generates these filters dynamically based on the tool's declared capabilities. A tool that needs network access gets socket, connect, and sendto. A tool that needs filesystem writes gets open, write, and unlink.
Observability Surface
Kernel-enforced boundaries change what you can observe. Traditional application metrics (request latency, error rate) still apply, but you also get:
- Syscall denial rate by tool and invocation
- Policy evaluation latency (allow-list lookup time)
- Phantom token validation failures
- Namespace creation and teardown time
- Audit log growth rate and Merkle root verification
The audit log is the primary observability artifact. It's append-only, cryptographically sealed, and contains every security decision. You can replay it to reconstruct the agent's behavior or prove compliance.
Technical Verdict
Use Nono when:
- You're running untrusted agent code in production
- Credential leakage or sandbox escape would cause material harm
- You need cryptographic proof of agent behavior for compliance
- You can tolerate 100-500μs latency per tool invocation
- You control the host kernel (not serverless)
Avoid Nono when:
- You're prototyping and don't need production-grade isolation
- Your agents run in serverless environments without kernel module support
- Latency budgets are sub-millisecond and you invoke tools at high frequency
- Your threat model doesn't include prompt injection or sandbox escape
Kernel-enforced boundaries are overkill for most side projects. They make sense when the cost of a breach exceeds the cost of the infrastructure.
Top comments (0)