For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
  • About NVIDIA OpenShell
    • Overview
    • How It Works
    • Installation
    • Container Gateway
    • Supported Agents
    • Release Notes
  • Get Started
    • Quickstart
    • Tutorials
  • Manage OpenShell
    • Sandboxes
    • Gateways
    • Providers
    • Providers v2
    • Policies
    • Policy Advisor
    • Inference Routing
  • Observability
    • Accessing Logs
    • Logging
    • OCSF JSON Export
  • Kubernetes
    • Setup
    • Managing Certificates
    • Ingress
    • Access Control
    • OpenShift
  • Reference
    • Gateway Auth
    • Default Policy
    • Policy Schema
    • Compute Drivers
    • Gateway Config
    • Support Matrix
  • Security
    • Security Best Practices
  • Resources
    • License
NVIDIANVIDIA
Developer-friendly docs for your API
Privacy Policy | Manage My Privacy | Do Not Sell or Share My Data | Terms of Service | Accessibility | Corporate Policies | Product Security | Contact

Copyright © 2026, NVIDIA Corporation.

LogoLogoOpenShell
On this page
  • Enforcement Layers
  • Network Controls
  • Deny-by-Default Egress
  • Network Namespace Isolation
  • User Namespace Isolation
  • Binary Identity Binding
  • L4-Only vs L7 Inspection
  • Enforcement Mode (audit vs enforce)
  • TLS Handling
  • SSRF Protection
  • Operator Approval
  • Filesystem Controls
  • Landlock LSM
  • Read-Only vs Read-Write Paths
  • Path Validation
  • Process Controls
  • Privilege Drop
  • Seccomp Filters
  • Enforcement Application Order
  • Inference Controls
  • Routed Inference through inference.local
  • Gateway Security
  • mTLS
  • SSH Tunnel Authentication
  • Common Mistakes
  • Related Topics
Security

OpenShell Security Best Practices for Controls, Risks, and Configuration Guidance

||View as Markdown|
Previous

Support Matrix

Next

License

OpenShell enforces sandbox security across four layers: network, filesystem, process, and inference. This page documents every configurable control, its default, what it protects, and the risk of relaxing it.

For the full policy YAML schema, refer to the Policy Schema. For the architecture of each enforcement layer, refer to How OpenShell Works.

If you use NemoClaw, its Security Best Practices guide covers additional entrypoint-level controls, policy presets, provider trust tiers, and posture profiles specific to the NemoClaw blueprint.

Enforcement Layers

OpenShell applies security controls at two enforcement points. OpenShell locks static controls at sandbox creation and requires destroying and recreating the sandbox to change them. You can update dynamic controls on a running sandbox with openshell policy update or openshell policy set.

LayerWhat it protectsEnforcement pointChangeable at runtime
NetworkUnauthorized outbound connections and data exfiltration.CONNECT proxy + OPA policy engineYes. Use openshell policy update, openshell policy set, or operator approval in the TUI.
FilesystemSystem binary tampering, credential theft, config manipulation.Landlock LSM (kernel level)No. Requires sandbox re-creation.
ProcessPrivilege escalation, fork bombs, dangerous syscalls.Seccomp BPF + privilege drop (setuid/setgid)No. Requires sandbox re-creation.
InferenceCredential exposure, unauthorized model access.Proxy intercept of inference.localYes. Use openshell inference set.

Network Controls

The CONNECT proxy and OPA policy engine enforce all network controls at the gateway level.

Deny-by-Default Egress

Every outbound connection from the sandbox goes through the CONNECT proxy. The proxy evaluates each connection against the OPA policy engine. If no network_policies entry matches the destination host, port, and calling binary, the proxy denies the connection.

AspectDetail
DefaultAll egress denied. Only endpoints listed in network_policies can receive traffic.
What you can changeAdd entries to network_policies in the policy YAML. Apply statically at creation (--policy) or dynamically (openshell policy update for incremental changes, openshell policy set for full replacement).
Risk if relaxedEach allowed endpoint is a potential data exfiltration path. The agent can send workspace content, credentials, or conversation history to any reachable host.
RecommendationAdd only endpoints the agent needs for its task. Start with a minimal policy and use denied-request logs (openshell logs <name> --source sandbox) to identify missing endpoints.

Network Namespace Isolation

The sandbox runs in a dedicated Linux network namespace with a veth pair. All traffic routes through the host-side veth IP (10.200.0.1) where the proxy listens. Even if a process ignores proxy environment variables, it can only reach the proxy.

AspectDetail
DefaultAlways active. The sandbox cannot bypass the proxy at the network level.
What you can changeThis is not a user-facing knob. OpenShell always enforces it in proxy mode.
Risk if bypassedWithout network namespace isolation, a process could connect directly to the internet, bypassing all policy enforcement.
RecommendationNo action needed. OpenShell enforces this automatically.

User Namespace Isolation

Kubernetes user namespaces (hostUsers: false) map container UID 0 to an unprivileged host UID. Capabilities like CAP_SYS_ADMIN become namespaced. They grant power over container-local resources only, not the host. This provides defense-in-depth: even if a container escape vulnerability exists, the attacker lands as an unprivileged host user.

AspectDetail
DefaultDisabled. Set server.enableUserNamespaces: true in Helm values or enable_user_namespaces = true in the gateway config to enable cluster-wide.
What you can changeEnable cluster-wide through Helm or gateway config. Override per-sandbox through the user_namespaces field on SandboxTemplate in the API.
PrerequisitesKubernetes 1.33+ with user namespace support available (beta through 1.35, GA in 1.36+), a container runtime that supports user namespaces (containerd 2.0+, CRI-O 1.25+), and Linux 5.12+ for ID-mapped mounts.
Risk if enabled with GPUNVIDIA device plugin compatibility with user namespaces is unverified. OpenShell logs a warning when both GPU and user namespaces are active on the same sandbox.
RecommendationEnable on non-GPU clusters running Kubernetes with user namespace support available (1.33+ beta, 1.36+ GA) for stronger host isolation. Test GPU workloads separately before enabling on GPU clusters.

Binary Identity Binding

The proxy identifies which binary initiated each connection by reading /proc/<pid>/exe (the kernel-trusted executable path). It walks the process tree for ancestor binaries and parses /proc/<pid>/cmdline for script interpreters. The proxy SHA256-hashes each binary on first use (trust-on-first-use). If someone replaces a binary mid-session, the hash mismatch triggers an immediate deny.

AspectDetail
DefaultEvery network_policies entry requires a binaries list. Only listed binaries can reach the associated endpoints. Binary paths support glob patterns (* for one path component, ** for recursive).
What you can changeAdd binaries to an endpoint entry. Use glob patterns for directory-scoped access (for example, /sandbox/.vscode-server/**).
Risk if relaxedBroad glob patterns (like /**) allow any binary to reach the endpoint, defeating the purpose of binary-scoped enforcement.
RecommendationScope binaries to the specific executables that need each endpoint. Use narrow globs when the exact path varies (for example, across Python virtual environments).

L4-Only vs L7 Inspection

The protocol field on an endpoint controls whether the proxy inspects individual HTTP requests inside the tunnel.

AspectDetail
DefaultEndpoints without a protocol field use L4-only enforcement: the proxy checks host, port, and binary, then relays the TCP stream without inspecting payloads.
What you can changeAdd protocol: rest to enable per-request HTTP method/path inspection, protocol: websocket to inspect RFC 6455 upgrade handshakes and client text messages, or protocol: graphql to inspect GraphQL-over-HTTP operation type, operation name, and root fields. WebSocket endpoints can also use GraphQL operation rules for GraphQL-over-WebSocket messages. Pair inspected protocols with rules or access presets (full, read-only, read-write). REST endpoints that need credential placeholders in supported text request bodies can set request_body_credential_rewrite: true.
Risk if relaxedL4-only endpoints allow the agent to send any data through the tunnel after the initial connection is permitted. The proxy cannot see HTTP methods, paths, or GraphQL operations. Adding access: full with L7 inspection enables observability but permits all inspected actions.
RecommendationUse protocol: rest with specific rules for APIs where intent is encoded in method and path. Add request_body_credential_rewrite: true only for REST APIs that require OpenShell-managed credentials in UTF-8 JSON, form, or text request bodies. Use protocol: graphql for GraphQL-over-HTTP APIs where destructive operations are body-encoded. Use protocol: websocket for RFC 6455 endpoints, with explicit GET and WEBSOCKET_TEXT rules for raw text protocols or explicit GraphQL operation rules for GraphQL-over-WebSocket. Prefer access: read-only or explicit allowlists, and deny hash-only persisted queries unless you maintain a trusted registry. Omit protocol for non-HTTP protocols. For WebSocket endpoints that must carry placeholder credentials in client text frames, add websocket_credential_rewrite: true.

Enforcement Mode (audit vs enforce)

When L7 inspection is active, the enforcement field controls whether the proxy blocks or logs rule violations.

AspectDetail
Defaultaudit. The proxy logs violations but forwards traffic.
What you can changeSet enforcement: enforce to block requests that do not match any rules entry. Denied requests receive a 403 Forbidden response with a JSON body describing the violation.
Risk if relaxedaudit mode provides visibility but does not prevent unauthorized actions. An agent can still perform write or delete operations on an API even if the rules would deny them.
RecommendationStart with audit to understand traffic patterns and verify that rules are correct. Switch to enforce after you validate that the rules match the intended access pattern.

TLS Handling

The proxy auto-detects TLS on every tunnel by peeking the first bytes. When a TLS ClientHello is detected, the proxy terminates TLS transparently using a per-sandbox ephemeral CA. This enables credential injection and L7 inspection without explicit configuration.

AspectDetail
DefaultAuto-detect and terminate. OpenShell generates the sandbox CA at startup and injects it into the process trust stores (NODE_EXTRA_CA_CERTS, DENO_CERT, SSL_CERT_FILE, REQUESTS_CA_BUNDLE, CURL_CA_BUNDLE, GIT_SSL_CAINFO).
What you can changeSet tls: skip on an endpoint to disable TLS detection and termination for that endpoint. Use this for client-certificate mTLS to upstream or non-standard binary protocols.
Risk if relaxedtls: skip disables credential injection and L7 inspection for that endpoint. The proxy relays encrypted traffic without seeing the contents.
RecommendationUse auto-detect (the default) for most endpoints. Use tls: skip only when the upstream requires the client’s own TLS certificate (mTLS) or uses a non-HTTP protocol.

SSRF Protection

After OPA policy allows a connection, the proxy resolves DNS and rejects connections where the resolved IP is internal (loopback, link-local, or RFC 1918 private).

AspectDetail
DefaultThe proxy blocks all private IPs. Loopback (127.0.0.0/8), link-local (169.254.0.0/16), and unspecified (0.0.0.0) addresses are always blocked and cannot be overridden with allowed_ips.
What you can changeAdd allowed_ips (CIDR notation) to an endpoint to permit connections to specific private IP ranges. On Linux, the proxy consults the sandbox’s /etc/hosts before DNS, so Kubernetes hostAliases can make LAN-only hostnames resolvable. Policies with allowed_ips entries that overlap loopback, link-local, or unspecified addresses fail to load with a clear validation error.
Risk if relaxedWithout SSRF protection, a misconfigured policy could allow the agent to reach cloud metadata services (169.254.169.254), internal databases, or other infrastructure endpoints through DNS rebinding.
RecommendationUse allowed_ips only for known internal services. Scope the CIDR as narrowly as possible (for example, 10.0.5.20/32 for a single host). Loopback, link-local, and unspecified addresses are always blocked regardless of allowed_ips. hostAliases change resolution, not authorization: host: searxng.local with /etc/hosts mapping to 192.168.1.105 still needs allowed_ips: ["192.168.1.105/32"]. The policy advisor does not propose rules for always-blocked destinations.

Operator Approval

When the agent requests an endpoint not in the policy, OpenShell blocks it and surfaces the request in the TUI for operator review. The system merges approved endpoints into the sandbox’s policy as a new durable revision.

AspectDetail
DefaultEnabled. The proxy blocks unlisted endpoints and requires approval.
What you can changeApproved endpoints persist across sandbox restarts within the same sandbox instance. They reset when the sandbox is destroyed and recreated.
Risk if relaxedApproving an endpoint permanently widens the running sandbox’s policy. Review each request before approving.
RecommendationUse operator approval for exploratory work. For recurring endpoints, add them to the policy YAML with appropriate binary and path restrictions. To reset all approved endpoints, destroy and recreate the sandbox.

Filesystem Controls

Landlock LSM restricts which paths the sandbox process can read or write at the kernel level.

Landlock LSM

Landlock enforces filesystem access at the kernel level. Paths listed in read_only receive read-only access. Paths listed in read_write receive full access. All other paths are inaccessible.

Landlock setup runs in two phases. The parent supervisor probes the kernel ABI and opens the configured path file descriptors before forking. The child then applies the ruleset with restrict_self() after privilege drop. At startup, OpenShell emits the selected ABI version and the applied read-only and read-write rule counts so you can confirm what the kernel accepted.

AspectDetail
Defaultcompatibility: best_effort. Uses the highest kernel ABI available. Missing paths are skipped. If the kernel does not support Landlock or any configured path cannot be opened, the sandbox continues without those restrictions and emits a High-severity OCSF DetectionFinding.
What you can changeSet compatibility: hard_requirement to abort sandbox startup if Landlock is unavailable or any configured path cannot be opened.
Risk if relaxedOn kernels without Landlock (pre-5.13), or when all paths fail to open, the sandbox runs without kernel-level filesystem restrictions. The agent can access any file the process user can access.
RecommendationUse best_effort for development. Use hard_requirement in environments where any gap in filesystem isolation is unacceptable. Treat High-severity Landlock findings as a signal to investigate the host kernel or the image. Run on Ubuntu 22.04+ or any kernel 5.13+ for Landlock support.

Read-Only vs Read-Write Paths

The policy separates filesystem paths into read-only and read-write groups.

AspectDetail
DefaultSystem paths (/usr, /lib, /etc, /var/log) are read-only. Working paths (/sandbox, /tmp) are read-write. /app is conditionally included if it exists.
What you can changeAdd or remove paths in filesystem_policy.read_only and filesystem_policy.read_write.
Risk if relaxedMaking system paths writable lets the agent replace binaries, modify TLS trust stores, or change DNS resolution. Validation rejects broad read-write paths (like /).
RecommendationKeep system paths read-only. If the agent needs additional writable space, add a specific subdirectory.

Path Validation

OpenShell validates policies before they take effect.

ConstraintBehavior
Paths must be absolute (start with /).Rejected with INVALID_ARGUMENT.
Paths must not contain .. traversal.Rejected with INVALID_ARGUMENT.
Read-write paths must not be overly broad (for example, / alone).Rejected with INVALID_ARGUMENT.
Each path must not exceed 4096 characters.Rejected with INVALID_ARGUMENT.
Combined read_only + read_write paths must not exceed 256.Rejected with INVALID_ARGUMENT.

Process Controls

The sandbox supervisor drops privileges, applies seccomp filters, and enforces process-level restrictions during startup.

Privilege Drop

The sandbox process runs as a non-root user after explicit privilege dropping.

AspectDetail
Defaultrun_as_user: sandbox, run_as_group: sandbox. The supervisor calls setuid()/setgid() with post-condition verification, disables core dumps with RLIMIT_CORE=0, and on Linux sets PR_SET_DUMPABLE=0.
What you can changeSet run_as_user and run_as_group in the process section. Validation rejects root (root or 0).
Risk if relaxedRunning as a higher-privilege user increases the impact of container escape vulnerabilities.
RecommendationKeep the sandbox user. Do not attempt to set root.

Seccomp Filters

OpenShell applies seccomp in two phases. A narrow supervisor-startup prelude runs before CLI parsing and async runtime initialization, then the child process receives the broader runtime seccomp filter after privilege drop.

AspectDetail
Startup preludeAfter privileged bootstrap helpers complete, the supervisor sets PR_SET_NO_NEW_PRIVS and synchronizes a seccomp filter across all runtime threads that blocks mount, the new mount API syscalls, pivot_root, umount2, bpf, perf_event_open, userfaultfd, module-loading syscalls, and kexec. This closes the long-lived privileged remount and kernel-surface window while leaving required setup syscalls such as setns available.
Socket domainsThe filter allows AF_INET and AF_INET6 (for proxy communication) and blocks AF_NETLINK, AF_PACKET, AF_BLUETOOTH, and AF_VSOCK with EPERM.
Runtime unconditional syscall blocksmemfd_create, ptrace, bpf, process_vm_readv, process_vm_writev, pidfd_open, pidfd_getfd, pidfd_send_signal, io_uring_setup, mount, fsopen, fsconfig, fsmount, fspick, move_mount, open_tree, setns, umount2, pivot_root, userfaultfd, perf_event_open.
Conditional syscall blocksexecveat with AT_EMPTY_PATH, unshare and clone with CLONE_NEWUSER, and seccomp(SECCOMP_SET_MODE_FILTER) are denied with EPERM.
What you can changeThis is not a user-facing knob. OpenShell enforces it automatically.
Risk if relaxedThe blocked syscalls support container escape (mount, pivot_root, move_mount, namespace creation), cross-process observation (ptrace, process_vm_readv, pidfd_*), raw kernel bypass (bpf, io_uring_setup, perf_event_open), and filter evasion (seccomp, userfaultfd).
RecommendationNo action needed. OpenShell enforces this automatically.

Enforcement Application Order

The sandbox supervisor applies enforcement in a specific order during process startup. This ordering is intentional: named network-namespace setup still relies on privileged helpers, and privilege dropping still needs /etc/group and /etc/passwd, which Landlock subsequently restricts.

  1. Privileged supervisor bootstrap helpers, including network-namespace setup and optional nft probes.
  2. Supervisor startup prelude seccomp (PR_SET_NO_NEW_PRIVS plus the early syscall denylist) synchronized across runtime threads.
  3. Network namespace entry (setns) in child pre_exec.
  4. Privilege drop (initgroups + setgid + setuid).
  5. Core-dump hardening (RLIMIT_CORE=0, plus PR_SET_DUMPABLE=0 on Linux).
  6. Landlock filesystem restrictions.
  7. Runtime seccomp socket domain and syscall filters.

Inference Controls

OpenShell routes all inference traffic through the gateway to isolate provider credentials from the sandbox.

Routed Inference through inference.local

The proxy intercepts HTTPS CONNECT requests to inference.local and routes matching inference API requests through the sandbox-local router. The agent never receives the provider API key.

AspectDetail
DefaultAlways active. The proxy handles inference.local before OPA policy evaluation. The gateway injects credentials on the host side.
Keep-alive isolationIf a sandbox reuses a keep-alive connection that previously carried a routed inference request for a subsequent non-inference request, the proxy denies the non-inference request with connection not allowed by policy and closes the connection. This prevents agents from reusing an inference-authorized connection for other destinations.
What you can changeConfigure inference routes with openshell inference set.
Risk if bypassedIf an inference provider’s host is added directly to network_policies, the agent could reach it with a stolen or hardcoded key, bypassing credential isolation.
RecommendationDo not add inference provider hosts to network_policies. Use OpenShell inference routing instead.

Gateway Security

The gateway secures communication between the CLI, sandbox workloads, and external clients with mutual TLS and token-based authentication.

mTLS

Gateway transport uses TLS, with client certificate checks available where the deployment provides a client CA. Local single-user Docker, Podman, and VM gateways can use the verified client certificate as user authentication. Kubernetes deployments use the certificate bundle for transport and sandbox supervisor connectivity only; configure OIDC or a trusted access proxy for user authentication.

AspectDetail
DefaultLocal TLS bundles enable mTLS user authentication for single-user local gateways. Helm deployments generate mTLS certificates for transport, while sandbox supervisors authenticate API calls with gateway-minted sandbox JWTs. TLS-enabled loopback gateways also accept plaintext HTTP for sandbox service hostnames by default.
What you can changeConfigure OIDC or a trusted access proxy for multi-user gateways, set OPENSHELL_ENABLE_MTLS_AUTH=true for local single-user gateways, enable server.auth.allowUnauthenticatedUsers=true only for trusted local Kubernetes development or a fully trusted proxy, disable TLS only for trusted reverse-proxy setups, or disable loopback service HTTP with --enable-loopback-service-http=false.
Risk if relaxedDisabling TLS removes transport-level protection entirely. Allowing unauthenticated users removes the gateway user-auth boundary and must not be exposed to shared or public networks. Treating transport certificates as shared user identity in Kubernetes would collapse user and sandbox trust boundaries. Loopback service HTTP is local-only and rejects cross-origin browser requests, but any local process can still reach exposed service URLs directly.
RecommendationUse local mTLS user authentication only for single-user Docker, Podman, and VM gateways. Use OIDC or a trusted access proxy for Kubernetes and shared deployments.

SSH Tunnel Authentication

SSH connections to sandboxes travel through the gateway over the sandbox supervisor’s authenticated control path. Each SSH connect call also carries a short-lived session token scoped to a specific sandbox. The sandbox never exposes an SSH port on the network. Its SSH daemon listens on a local Unix socket that only the sandbox’s own supervisor process can reach.

AspectDetail
DefaultSession tokens expire after 24 hours. Concurrent connections are limited to 10 per token and 20 per sandbox.
What you can changeConfigure ssh_session_ttl_secs. Set to 0 for no expiry.
Risk if relaxedLonger TTLs or no expiry increase the window for stolen token reuse. Higher connection limits increase the blast radius of a compromised token.
RecommendationKeep the 24-hour default. Monitor connection counts through the TUI.

Common Mistakes

The following patterns weaken security without providing meaningful benefit.

MistakeWhy it mattersWhat to do instead
Omitting an inspected protocol on REST or WebSocket API endpointsWithout protocol: rest or protocol: websocket, the proxy uses L4-only enforcement. It allows the TCP stream through after checking host, port, and binary, but cannot inspect individual HTTP requests or WebSocket text messages.Add protocol: rest or protocol: websocket with specific rules to enable method and path control.
Using access: full when finer rules would sufficeaccess: full with protocol: rest or protocol: websocket enables inspection but allows all methods and paths for that protocol.Use access: read-only or explicit rules to restrict what the agent can do at the L7 level.
Adding endpoints permanently when operator approval would sufficeAdding endpoints to the policy YAML makes them permanently reachable across all instances.Use operator approval. Approved endpoints persist within the sandbox instance but reset on re-creation.
Using broad binary globsA glob like /** allows any binary to reach the endpoint, defeating binary-scoped enforcement.Scope globs to specific directories (for example, /sandbox/.vscode-server/**).
Skipping TLS termination on HTTPS APIsSetting tls: skip disables credential injection and L7 inspection.Use the default auto-detect behavior unless the upstream requires client-certificate mTLS.
Setting enforcement: enforce before auditingJumping to enforce without first running in audit mode risks breaking the agent’s workflow.Start with audit, review the logs, and switch to enforce after you validate the rules.

Related Topics

  • Policies for applying and iterating on sandbox policies.
  • Policy Schema for the full field-by-field YAML reference.
  • Default Policy for the built-in default policy breakdown.
  • Gateway Auth for gateway authentication details.
  • How OpenShell Works for the system architecture.
  • NemoClaw Security Best Practices for entrypoint-level controls (capability drops, PATH hardening, build toolchain removal), policy presets, provider trust tiers, and posture profiles.