DEV Community

Cover image for Nono: Kernel-Enforced Security Boundaries for AI Agent Runtime Isolation
mech.app
mech.app

Posted on Originally published at mech.app

Nono: Kernel-Enforced Security Boundaries for AI Agent Runtime Isolation

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:

  1. Resolves and verifies the executable (Sigstore supply chain integrity)
  2. Evaluates argv policy for the caller and arguments
  3. Creates an invocation-scoped micro sandbox with bounded capabilities
  4. Injects a phantom credential token (real token stays with supervisor)
  5. 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:

  1. Proxy receives request with phantom token
  2. Proxy validates token against invocation context
  3. Proxy evaluates HTTP method and path against policy
  4. Proxy injects real credential at boundary
  5. 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);
Enter fullscreen mode Exit fullscreen mode

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.

Source Links

Top comments (0)