nono Sandboxing Environment

repository·main·Indexed 25 days ago

https://github.com/nolabs-ai/nono

A zero-latency, zero-setup capability-based sandboxing environment for running AI agents. It provides least-privilege isolation for agents and tools without requiring containers or VMs, utilizing Landlock on Linux (Kernel 5.13+) and Seatbelt on macOS (10.5+). The ecosystem includes nono-cli for command execution and profile management, nono-proxy for network filtering and credential injection, and a Rust library for applying irreversible sandboxes via CapabilitySets.

Tokens
116.4K
Snippets
338
Records
602
Agent score
86%

What's inside nono

  1. Understand the nono Workspace Architecture

    main

    The nono project is organized into several crates with distinct responsibilities. Understanding these boundaries is critical for both development and integration:

    • crates/nono (Core Library): The policy-free sandbox primitive. It handles the capability model, path canonicalization, Landlock/Seatbelt application, diagnostics, keystore helpers, host filtering, trust/attestation types, rollback object storage, and supervisor protocol types. It only applies capabilities explicitly supplied by the caller.
    • crates/nono-cli (CLI & Runtime): The layer for user policy, embedded profiles, policy group resolution, protected path handling, execution strategy selection, environment preparation, proxy runtime wiring, credential loading, audit, rollback, trust commands, package/registry workflows, and ephemeral tool isolation.
    • crates/nono-proxy (Network Proxy): A network proxy running outside the child sandbox. It provides controlled loopback access to the sandboxed child and implements CONNECT host filtering, reverse proxy credential injection, external proxy chaining, TLS interception (L7), endpoint filtering, OAuth2, and optional SPIFFE support.
    • bindings/c (nono-ffi): The C ABI wrapper around the core library. Use this for FFI-based integrations, ensuring pointer validity, ownership, and allocation/free symmetry.
  2. Understand nono's security trust boundaries

    main

    nono operates using three primary trust domains to ensure the sandboxed process remains untrusted and contained:

    1. Kernel: The fully trusted layer that enforces Landlock rules, delivers seccomp notifications, and blocks unauthorized syscalls.
    2. Supervisor (parent): The trusted layer that records audit events, receives trapped syscalls, consults approval backends, opens files, and injects file descriptors. It also manages the network proxy and PTY relay.
    3. Sandboxed child: The untrusted layer where the agent command runs under full kernel enforcement.

    When proxy mode is active, a fourth domain is added:

    • Network proxy: A trusted component running within the supervisor that filters outbound connections by host, injects credentials, and enforces deny CIDRs. The sandboxed child is restricted to localhost:<port> via kernel-level blocking; all other outbound TCP is prevented.
  3. Use nono-proxy for network filtering and credential injection

    main
    The nono-proxy crate provides host-level network filtering and credential injection for sandboxed processes. It is designed to run unsandboxed in a supervisor process while restricting child processes to connecting only to the proxy's localhost port via NetworkMode::ProxyOnly.
  4. Understand the nono Security Model and Supervisor Role

    main

    The nono security model relies on a supervisor-child architecture. The supervisor (the parent process) is a non-privileged Rust binary that manages the sandbox. It is designed to be a privilege boundary in the downward direction (restricting the child) rather than an upward escalation vector.

    Key security properties:

    • Unprivileged Execution: The supervisor runs as the same user who invoked nono run. It does not require root, CAP_SYS_ADMIN, or setuid permissions.
    • Memory Safety: The supervisor is written in Rust, which prevents common vulnerabilities like buffer overflows and use-after-free. IPC (Inter-Process Communication) uses length-prefixed JSON parsed via serde.
    • Isolation: There is no shared memory, no signal-based control channel, and the child is prevented from using ptrace on the supervisor.
    • Minimal Attack Surface: The supervisor's IPC socket is an anonymous socketpair(), and its network exposure is limited to a random localhost port protected by a session token when in proxy mode.
  5. Security properties of credential injection

    main

    Nono provides several security guarantees for credential handling:

    • Sandbox Isolation: Credentials never enter the sandbox; the agent process has no access to API keys via environment variables or memory.
    • Session Token Isolation: Credential routes validate the phantom token in the configured header, path, or query parameter.
    • Managed Secret Sources: Supports OS keyring, 1Password, Bitwarden, Apple Passwords, explicit files, or host environment variables.
    • Memory Safety: Credential values are stored in Zeroizing<String> and wiped from memory on drop.
    • Session Scoping: Credentials are loaded once at proxy startup and are never written to disk or logged.
    • Header Stripping: Credential routes strip the configured credential header and hop-by-hop headers before injection. No-credential routes pass application headers (like Authorization) through.
  6. Understand the two-layer sandbox architecture

    main

    nono employs a defense-in-depth strategy using two distinct kernel mechanisms:

    Layer 1: Landlock (The Floor)

    Landlock provides a permanent, irreversible security floor. Once restrict_self() is called, the child process is restricted to its initial capability set. This layer is unprivileged and inherited by all child processes/threads. It ensures that even if the supervisor fails, the child cannot access paths outside its allowed set.

    Layer 2: seccomp-notify (The Gate)

    This layer provides dynamic capability expansion. A BPF filter traps openat and openat2 syscalls and routes them to the supervisor.

    • Deny: The supervisor returns EPERM (the syscall never reaches Landlock).
    • Approve: The supervisor opens the file itself and injects the file descriptor into the child via SECCOMP_IOCTL_NOTIF_ADDFD.

    Critical Ordering: seccomp runs before Landlock. This allows the supervisor to grant temporary access to files that Landlock would otherwise block, while Landlock acts as a fallback to catch any supervisor errors or escapes.

  7. Understand nono's security model and guarantees

    main

    nono uses a capability-based security model with kernel-level enforcement based on a deny by default, allow explicitly principle. When running a command through nono, only explicitly granted access is permitted; all other access is blocked at the kernel level.

    Security Guarantees

    • Path Traversal Protection: Prevents escaping allowed directories using ../ sequences.
    • Symlink Escape Protection: Paths are canonicalized at grant time to prevent symlinks from pointing outside the sandbox.
    • Credential Theft Protection: Sensitive paths (like SSH, AWS, or Kubernetes configs) are blocked by default even if a parent directory is allowed.
    • Child Process Isolation: All child processes inherit the sandbox restrictions.
    • Privilege Escalation Prevention: The sandbox is applied before exec(), ensuring no window of elevated privilege exists.

    Security Limitations

    • Kernel Exploits: Does not protect against vulnerabilities in the host kernel.
    • Covert Channels: Does not prevent information leakage via timing or CPU usage patterns.
    • Resource Exhaustion: Does not limit CPU, memory, or disk usage (no DoS protection).
    • Data within Allowed Paths: If a directory is granted, all files within it are accessible.
    • TOCTOU Races: A minimal window exists between path canonicalization and sandbox application.
  8. Understand nono's OS-level sandboxing architecture

    main

    nono provides security by using kernel-enforced sandboxing (via Landlock or Seatbelt) rather than application-level permission checks. This ensures that even if an agent is compromised, performs a prompt injection, or loads a malicious dependency, it cannot bypass the security boundaries because the enforcement happens in kernel space, not within the agent's own process.

    Key security properties include:

    • Irreversibility: Once the sandbox is initialized (e.g., via landlock_restrict_self()), there is no API to undo the restrictions.
    • Enforcement Authority: The kernel intercepts system calls before they succeed, preventing unauthorized access.
    • Process Inheritance: All child processes spawned by a sandboxed agent automatically inherit the same restrictions.
    • Reduced Attack Surface: By relying on battle-tested kernel implementations, nono avoids common application-level bugs like symlink bypasses or TOCTOU (Time-of-Check to Time-of-Use) race conditions.
  9. Understand the Profile JSON Schema Restructure (Issue #594)

    main

    The nono profile JSON schema is undergoing a restructure to improve clarity and safety. The new schema moves away from a top-level policy key and introduces more granular control over groups, commands, and filesystem access.

    Key Changes:

    • Groups: Uses groups.include and groups.exclude instead of legacy policy structures.
    • Commands: Uses commands.allow and commands.deny.
    • Filesystem: Expanded to include deny and bypass_protection (formerly override_deny).
    • Security: Narrowed scope to remove redundant top-level keys.

    Implementation Note: The system uses a two-layer parsing approach. Canonical structs use #[serde(deny_unknown_fields)] to ensure strictness, while transient legacy-capture types (like LegacyPolicyPatch and RawSecurityConfig) handle backward compatibility by draining old keys into the new canonical format during deserialization.

  10. Understand Supervisor Mode Audit Responsibilities

    main

    The supervisor acts as the trusted recorder for supervised sessions. Because the supervisor is outside the sandbox, the sandboxed child cannot tamper with its own audit logs. The supervisor is responsible for:

    • Creating the audit session directory and writing session metadata.
    • Recording supervisor-observed events (e.g., capability decisions, URL opens).
    • Draining proxy network audit events at the end of the session.
    • Computing the audit-log chain head and Merkle root if --audit-integrity is enabled.
  11. Understand the nono security model and isolation scope

    main

    nono is a capability-based sandbox that provides fine-grained, kernel-enforced isolation at the OS syscall level. It is designed for agents acting within an operating context, providing precise control over paths, domains, sockets, environment variables, and operations.

    Key Distinctions:

    • What it is: A tool for per-path and per-operation capability control using Landlock (Linux) or Seatbelt (macOS).
    • What it is not: It is not a hypervisor (like Firecracker) or a container runtime. It does not provide a separate kernel boundary or hardware-level memory isolation; the sandboxed process shares the host kernel.
    • Policy Dependency: The effectiveness of nono depends on the accuracy of the applied policy. Because filesystem layouts vary across Linux distributions, policies must be tuned to the specific environment to avoid gaps.

    Deployment Posture Recommendation: For highest-assurance deployments, use a layered approach:

    1. Outer Perimeter: Use a lightweight VM (e.g., Firecracker) or hardened container runtime (e.g., Edera, Kata) for hardware-level isolation and namespace separation.
    2. Inner Granularity: Run nono inside that boundary to provide fine-grained capability control (e.g., restricting access to specific files within a mounted directory).
  12. Understand the nono sandbox capabilities

    main

    When running a client through nono, the sandbox enforces the following restrictions:

    • File Access: Only directories and files explicitly granted are accessible.
    • Sensitive Paths: Paths like ~/.ssh and ~/.aws are blocked by default.
    • Network: Network access can be allowed or blocked based on the profile configuration.
    • Inheritance: All child processes spawned by the agent inherit the same sandbox restrictions.
    • Escalation: The sandbox cannot be escaped at runtime; expanding permissions requires explicit supervisor approval (Linux only).