# Security This document describes the threat model, security mechanisms, and known limitations of agentsh. ## Overview agentsh is a security sandbox for AI agent command execution. It interposes between an AI agent and the host system to enforce policies on file access, network connections, command execution, and environment variables. ## Threat Model ### What agentsh Protects Against agentsh is designed to mitigate risks from **semi-trusted AI agents** operating within a defined workspace: | Threat | Protection | |--------|------------| | Arbitrary file access | FUSE filesystem with policy-based access control | | Credential theft via files | Deny rules for `.ssh/`, `.aws/`, `.env`, etc. | | Credential theft via environment | Deny list for secrets + dangerous vars (LD_PRELOAD, etc.) | | Unauthorized network access | eBPF/policy-based network filtering | | Dangerous command execution | Command allowlists with args pattern matching; kernel-level enforcement via seccomp or ptrace | | Resource exhaustion | cgroup limits (memory, CPU, PIDs) | | Destructive operations | Approval workflows, soft-delete to trash, checkpoint/rollback | | PII leakage to LLMs | Embedded proxy with DLP redaction before requests reach provider | | Untracked LLM usage | Request/response logging with token usage for cost attribution | | Unauthorized signal delivery | Signal interception with policy-based allow/deny/redirect | | Process termination attacks | Signal rules blocking fatal signals to external/system processes | ### What agentsh Does NOT Protect Against agentsh is **not** a full security sandbox like a VM or container with seccomp. It does not protect against: | Threat | Reason | |--------|--------| | **Kernel exploits** | Runs in userspace; kernel bugs bypass all protections | | **Root-level attacks** | Assumes agent runs as unprivileged user | | **Hardware side-channels** | No protection against Spectre/Meltdown-class attacks | | **Malicious agentsh binary** | Assumes agentsh itself is not compromised | | **Pre-existing malware** | Does not scan for or remove existing threats | | **Social engineering** | Cannot prevent agent from outputting phishing content | | **Denial of service to host** | Resource limits help but don't fully prevent | ### Trust Boundaries ``` ┌─────────────────────────────────────────────────────────────┐ │ HOST SYSTEM │ │ ┌───────────────────────────────────────────────────────┐ │ │ │ agentsh daemon │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌──────────────┐ │ │ │ │ │ Policy │ │ FUSE │ │ eBPF │ │ │ │ │ │ Engine │ │ Intercept │ │ Network │ │ │ │ │ └─────────────┘ └─────────────┘ └──────────────┘ │ │ │ │ ┌─────────────┐ ┌─────────────┐ │ │ │ │ │ Ptrace │ │ Seccomp │ │ │ │ │ │ Intercept │ │ Filter │ │ │ │ │ └─────────────┘ └─────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────┐ │ │ │ │ │ AGENT SANDBOX │ │ │ │ │ │ • Restricted file access (/workspace only) │ │ │ │ │ │ • Filtered environment variables │ │ │ │ │ │ • Controlled network egress │ │ │ │ │ │ • Resource limits (cgroups) │ │ │ │ │ └─────────────────────────────────────────────────┘ │ │ │ └───────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` **Trust assumptions:** - The host kernel is trusted - The agentsh binary is trusted - Policy files are trusted (not writable by agent) - The AI agent is semi-trusted (may attempt policy violations) ## Security Mechanisms ### File Access Control (FUSE) - Virtual filesystem mounted at `/workspace` - All file operations intercepted and checked against policy - Symlink escape prevention via `EvalSymlinks` + boundary checks - Operations: read, write, create, delete, chmod, rename, etc. **Policy evaluation:** First matching rule wins. Default is deny. #### Deferred FUSE Mounting In some environments (E2B, Firecracker, or other snapshot-based sandboxes), `/dev/fuse` is not accessible at session creation time but becomes available later at runtime. Deferred FUSE mounting delays the mount until the first `exec` call, then mounts idempotently. **When to use:** - Snapshot-restore environments where device permissions change at runtime - Firecracker microVMs where `/dev/fuse` is gated behind a readiness marker - Any setup where FUSE availability is delayed relative to session creation **Configuration:** ```yaml sandbox: fuse: enabled: true deferred: true # Optional: only run enable command when this file exists deferred_marker_file: "/tmp/.agentsh-fuse-enabled" # Optional: command to make /dev/fuse accessible deferred_enable_command: ["sudo", "/bin/chmod", "666", "/dev/fuse"] ``` **Behavior:** - On each `exec`, `ensureFUSEMount` checks if FUSE is already mounted (idempotent no-op if so) - Calls `Recheck()` on the filesystem interceptor to re-probe `/dev/fuse` - If still unavailable and `deferred_enable_command` is configured, runs the command (gated by `deferred_marker_file` if set) - On success, mounts the FUSE overlay and emits a `fuse_mounted` event with `"deferred": true` - On failure, emits `fuse_mount_failed` and continues without FUSE (non-blocking) **Security considerations:** - The enable command runs as the agentsh process (not as the agent). If it uses `sudo`, ensure the sudoers policy is scoped to the specific command. - The marker file should be writable only by trusted infrastructure (not by the agent), since its presence triggers the enable command. - If `deferred_enable_command` is empty, no automatic enable is attempted — FUSE must become available through external means. ### Network Control (eBPF) - Attaches to process cgroup before execution begins - Filters connections by domain, CIDR, and port - DNS resolution for domain-based rules (with timeout) **Race condition mitigation:** Processes start in ptrace-stopped state; eBPF attaches before process resumes. ### Command Execution - Pre-execution policy check on command + arguments - Three matching modes: - **Basename:** `sh` matches any path ending in `/sh` - **Full path:** `/bin/sh` matches only that exact path - **Glob pattern:** `/usr/*/python3` matches `/usr/bin/python3`, `/usr/local/python3` - Args pattern matching for dangerous flag combinations - **Path canonicalization:** `filepath.EvalSymlinks` resolves symlinks before policy evaluation, preventing bypass via symlinks or `/proc/self/root` paths (relative path resolution is applied for `execveat` calls) - **Transparent command unwrapping:** Wrapper commands (env, sudo, nice, ld-linux, etc.) are unwrapped to find the real payload; both wrapper and payload are evaluated with the most restrictive decision winning **Default behavior:** Deny if no rule matches. ### Command Execution Enforcement (ptrace) In environments where seccomp user-notify is unavailable (e.g. AWS Fargate, restricted containers), agentsh uses ptrace-based syscall interception as an alternative enforcement mechanism. **Implementation:** - Uses `PTRACE_SEIZE` to attach without stopping the target process - Intercepts `execve(2)` and `execveat(2)` syscalls at entry - Reads filename and argv from tracee process memory via `/proc//mem` - Evaluates the same policy rules as seccomp mode - Deny: sets syscall number to -1 (invalid), then fixes up return value with `-EACCES` on exit - Auto-attaches to fork/clone/vfork children via `PTRACE_O_TRACECLONE`/`TRACEFORK`/`TRACEVFORK` **Security properties:** - Kernel-level enforcement: the denied syscall never executes - Process tree tracking: all descendants are traced, preventing escape via fork+exec - `execveat` with `AT_EMPTY_PATH` (fd-based exec) is intercepted alongside regular `execve` - Path resolution: relative paths and fd-based paths are resolved to absolute paths for policy evaluation **Limitations:** - Currently intercepts execve/execveat only (Phase 1); file, network, and signal syscalls are classified but auto-allowed - Small race window between fork and ptrace auto-attach - Requires `SYS_PTRACE` capability (Linux-only) **Configuration:** See [Security Modes - Ptrace Configuration](docs/security-modes.md#ptrace-configuration). ### Environment Variables - Deny list for known secrets (AWS keys, API tokens, etc.) - Deny list for code injection vectors: - Linux: `LD_PRELOAD`, `LD_LIBRARY_PATH`, `LD_AUDIT` - macOS: `DYLD_INSERT_LIBRARIES`, `DYLD_LIBRARY_PATH` - Languages: `PYTHONPATH`, `NODE_OPTIONS`, `RUBYLIB`, `PERL5LIB` - Shell: `BASH_ENV`, `ENV`, `PROMPT_COMMAND` - Allow/deny patterns configurable per-policy **Operator-trusted injection (`env_inject`):** The `sandbox.env_inject` configuration allows operators to inject environment variables that bypass policy filtering. This is intentionally powerful and should only be used by operators with config file access. Primary use case: Setting `BASH_ENV` to point to a script that disables shell builtins (`kill`, `enable`, `ulimit`) which would otherwise bypass seccomp enforcement. ```yaml sandbox: env_inject: BASH_ENV: "/usr/lib/agentsh/bash_startup.sh" ``` **Security properties:** - `env_inject` values bypass the deny list (operator explicitly wants them) - Policy-level `env_inject` overrides global config (for per-policy customization) - Trust boundary: config file access (not user-controllable) ### Resource Limits (cgroups v2) - Memory limits (with swap disabled) - CPU quota - Process count limits - Command and session timeouts ### Signal Interception (Linux) agentsh intercepts signal delivery between processes using seccomp user-notify, providing policy-based control over which signals can reach which targets. **Implementation:** - Uses `SECCOMP_RET_USER_NOTIF` to trap signal syscalls (`kill`, `tkill`, `tgkill`, etc.) - PID registry tracks all processes in the session for target classification - Policy rules evaluated based on signal, sender, and target relationship **Target Classification:** | Target Type | Description | |-------------|-------------| | `self` | Process signaling itself | | `children` | Direct child processes | | `descendants` | All descendant processes | | `session` | Any process in agentsh session | | `external` | PIDs outside session | | `system` | PID 1 and kernel threads | **Decision Types:** | Decision | Behavior | |----------|----------| | `allow` | Signal delivered normally | | `deny` | Returns EPERM to sender | | `redirect` | Changes signal (e.g., SIGKILL → SIGTERM) | | `audit` | Allow + log event | **Platform Support:** - **Linux**: Full blocking and redirect via seccomp user-notify - **macOS**: Audit only via Endpoint Security Framework - **Windows**: Partial blocking via ETW See [Policy Documentation](docs/operations/policies.md#signal-rules) for configuration examples. ### Approval Workflows Risky operations can require human approval before execution. agentsh supports multiple approval modes: **Approval Modes:** - `local_tty`: Interactive terminal prompt with math challenge (default) - `api`: Remote approval via REST API (for headless/remote deployments) - `totp`: Time-based One-Time Password via authenticator app (Google Authenticator, Authy, etc.) - `webauthn`: Hardware security key verification (YubiKey, platform authenticators) - highest security **Key Features:** - Configurable timeout (default: deny on timeout) - Audit logging of all approval decisions - Credential separation prevents agents from self-approving - WebAuthn provides cryptographic proof of human presence See [Approval Authentication](docs/approval-auth.md) for detailed configuration. ### Checkpoint and Rollback agentsh provides workspace checkpoint and rollback capabilities for recovery from destructive operations: **Core Features:** - **Copy-on-write snapshots**: File contents backed up before risky commands - **Hash verification**: SHA-256 verification ensures rollback integrity - **Auto-checkpoint triggers**: Automatic checkpoints before rm, mv, git reset, etc. - **Diff inspection**: Compare current workspace to checkpoint state - **Purge management**: Retention policies for storage management **CLI Commands:** ```bash # Create manual checkpoint agentsh checkpoint create --session --workspace /path # List checkpoints agentsh checkpoint list --session # Show checkpoint details and diff agentsh checkpoint show --session --workspace /path --diff # Preview rollback (dry-run) agentsh checkpoint rollback --session --workspace /path --dry-run # Perform rollback agentsh checkpoint rollback --session --workspace /path # Purge old checkpoints agentsh checkpoint purge --session --older-than 24h --keep 10 ``` **Auto-Checkpoint Configuration:** ```yaml sessions: checkpoints: enabled: true storage_dir: /var/lib/agentsh/checkpoints max_per_session: 50 auto_checkpoint: enabled: true triggers: - rm - mv - git reset - git checkout - git clean - git stash retention: max_age: 168h # 7 days ``` **Default Auto-Checkpoint Triggers:** | Command | Risk | |---------|------| | `rm`, `rmdir`, `unlink` | File deletion | | `mv`, `rename` | File movement (source lost) | | `git reset` | Uncommitted changes lost | | `git checkout` | Local modifications discarded | | `git clean` | Untracked files deleted | | `git stash` | Changes stashed (may be forgotten) | **Safety Features:** - Skips files larger than 100MB by default - Skips hidden directories (.git, etc.) - Dry-run mode for rollback preview - Hash verification prevents corrupted restores **Limitations:** - Checkpoints only cover files, not external state (databases, APIs) - Large workspaces may require significant storage - Cannot checkpoint files outside the workspace ### External KMS Integration agentsh supports external Key Management Systems for HMAC keys used in audit integrity chains: **Supported Providers:** | Provider | Key Source | Envelope Encryption | |----------|------------|---------------------| | File/Env | Local file or environment variable | No | | AWS KMS | AWS Key Management Service | Yes (GenerateDataKey) | | Azure Key Vault | Azure Key Vault secrets | No (direct secret) | | HashiCorp Vault | Vault KV v1/v2 secrets | No (direct secret) | | GCP Cloud KMS | Google Cloud KMS | Yes (Encrypt/Decrypt) | **Configuration Examples:** ```yaml # AWS KMS (envelope encryption) audit: integrity: enabled: true key_source: aws_kms aws_kms: key_id: "arn:aws:kms:us-east-1:123456789:key/abc-123" region: us-east-1 encrypted_dek_file: /etc/agentsh/audit-dek.enc # Cache encrypted DEK # Azure Key Vault audit: integrity: enabled: true key_source: azure_keyvault azure_keyvault: vault_url: "https://myvault.vault.azure.net" key_name: "agentsh-audit-key" key_version: "" # Empty = latest # HashiCorp Vault audit: integrity: enabled: true key_source: hashicorp_vault hashicorp_vault: address: "https://vault.example.com:8200" auth_method: kubernetes # token, kubernetes, approle kubernetes_role: agentsh secret_path: "secret/data/agentsh/audit-key" key_field: "hmac_key" # GCP Cloud KMS audit: integrity: enabled: true key_source: gcp_kms gcp_kms: key_name: "projects/my-proj/locations/us/keyRings/agentsh/cryptoKeys/audit" encrypted_dek_file: /etc/agentsh/audit-dek.enc ``` **Authentication:** - **AWS**: Uses default credential chain (env vars, shared config, IAM role) - **Azure**: Uses DefaultAzureCredential (managed identity, CLI, env vars) - **Vault**: Supports token, Kubernetes, and AppRole authentication - **GCP**: Uses Application Default Credentials **Key Caching:** - Keys are cached in memory after first retrieval - For envelope encryption (AWS/GCP), encrypted DEK can be cached to disk - Key refresh requires service restart ### Authentication and Authorization agentsh supports multiple authentication methods for API access: **Authentication Types:** - `api_key`: Static API keys with role-based access (agent, approver, admin) - `oidc`: OpenID Connect/OAuth 2.0 for enterprise SSO integration (Okta, Azure AD, etc.) - `hybrid`: Both API key and OIDC accepted (API key takes precedence) **OIDC Features:** - JWT validation with JWKS auto-discovery - Group-based role mapping (groups containing "admin" or "approver" keywords) - Allowed groups filtering for access control - Token caching with secure hashing **Role Separation:** - `agent` role: Can execute commands, cannot approve - `approver` role: Can view and resolve approval requests - `admin` role: Full access including policy management ```yaml # Example hybrid auth configuration auth: type: hybrid api_key: keys_file: /etc/agentsh/api-keys.yaml oidc: issuer: "https://corp.okta.com" client_id: "agentsh" audience: "agentsh" allowed_groups: ["agentsh-operators"] ``` ### MCP Security agentsh provides comprehensive security controls for Model Context Protocol (MCP) tool invocations: #### Tool Whitelisting Policy-based control over which MCP tools can be invoked: ```yaml sandbox: mcp: enforce_policy: true fail_closed: true tool_policy: allowlist allowed_tools: - server: "filesystem" tool: "read_file" - server: "github" tool: "*" ``` | Policy Mode | Behavior | |-------------|----------| | `allowlist` | Only explicitly listed tools are permitted | | `denylist` | Listed tools are blocked, all others allowed | | `none` | No policy enforcement | #### Version Pinning Detect and optionally block MCP tool definition changes (rug pull detection): ```yaml sandbox: mcp: version_pinning: enabled: true on_change: block # block, alert, allow auto_trust_first: true ``` CLI management: ```bash agentsh mcp pins list agentsh mcp pins trust --server github --tool create_issue --hash sha256:... agentsh mcp pins reset --server github --tool create_issue ``` #### Rate Limiting Token bucket rate limiting for MCP calls and network requests: ```yaml sandbox: mcp: rate_limits: enabled: true default_rpm: 120 default_burst: 20 per_server: "slow-api": calls_per_minute: 30 burst: 5 network: rate_limits: enabled: true global_rpm: 600 global_burst: 50 per_domain: "api.openai.com": requests_per_minute: 60 burst: 10 ``` ### LLM Proxy and Data Loss Prevention (DLP) agentsh includes an embedded HTTP proxy that intercepts all LLM API requests from agents: **Architecture:** - Proxy starts automatically with each session on a random port - Agent environment is configured to route through proxy (`ANTHROPIC_BASE_URL`, `OPENAI_BASE_URL`) - Requests are intercepted, processed, and forwarded to upstream LLM providers **DLP Redaction:** - Request bodies are scanned for PII using regex patterns - Matches are replaced with `[REDACTED:pattern_type]` before forwarding - Built-in patterns: email, phone, credit card, SSN, API keys - Custom patterns can be defined for organization-specific data **Audit Logging:** - All requests and responses logged to session storage (JSONL format) - Token usage extracted and normalized across providers - Redaction events tracked with field paths and pattern types **Dialect Detection:** - Anthropic: `x-api-key` or `anthropic-version` headers - OpenAI API: `Authorization: Bearer sk-*` tokens - ChatGPT: OAuth tokens (non-sk- Bearer tokens) **Limitations:** - Only scans text content (not images or encoded data) - Regex patterns may miss obfuscated PII - Agent could theoretically bypass proxy (combine with network rules for defense in depth) See [LLM Proxy Documentation](docs/llm-proxy.md) for configuration and usage details. ## Known Limitations ### TOCTOU (Time-of-Check-Time-of-Use) File policy is checked when a file is opened. Between open and subsequent reads/writes, the underlying file could theoretically change (e.g., via hard links from outside the sandbox). This is inherent to userspace filesystem interception. **Mitigation:** The window is small, and the agent cannot create hard links to files outside `/workspace`. ### DNS Rebinding Network rules based on domain names resolve DNS at connection time. An attacker controlling DNS could potentially: 1. Resolve `evil.com` to an allowed IP during policy check 2. Change DNS to point to a blocked IP for actual connection **Mitigation:** Use CIDR rules for critical blocks (e.g., metadata services at `169.254.169.254/32`). Domain rules are convenience, not security boundaries. ### Process Tree Escapes If the eBPF/cgroup attachment fails after process start, child processes might execute before controls are in place. **Mitigation:** Ptrace-stopped start ensures attachment completes before any user code runs. Hook failures result in process termination. ### Transparent Unwrap Heuristic The transparent command unwrapping uses a simple heuristic to identify payload arguments (skip flags, env assignments, stop at first non-flag arg). This may misidentify a flag's value as the payload in some edge cases (e.g., `nice -n 10 wget` identifies `10` as the payload, not `wget`). **Mitigation:** Misidentified payloads don't match any command rule and hit default-deny, which is the safe outcome. Network enforcement provides a backstop for the actual payload command. ### Approval Bypass via Timing If an approval request times out, the operation is denied. However, a patient attacker could retry until a human mistakenly approves. **Mitigation:** Audit logging; approval fatigue is a human factors problem. ## Platform-Specific Limitations ### macOS (darwin) > **Alpha:** Native macOS enforcement via ESF+NE is in Alpha. It is functional end-to-end but not production-ready. For production macOS deployments, use Lima VM mode or Linux. macOS has significantly reduced security enforcement compared to Linux due to platform limitations: | Component | Linux | macOS | Impact | |-----------|-------|-------|--------| | File blocking | FUSE (enforced) | ESF (enforced via sysext) | **Enforced with system extension** | | Network blocking | eBPF/iptables | pf (loopback only) | **Network policies incomplete** | | Process isolation | Namespaces | sandbox-exec (minimal) | **Minimal isolation via SBPL profiles** | | Resource limits | cgroups v2 | None | Memory/CPU limits not enforced | | Syscall filtering | seccomp | None | Cannot restrict syscalls | | Process tracking | ptrace/wait | Polling (100ms) | Processes may escape detection | **Security tiers on macOS:** | Tier | Score | Requirements | Capabilities | |------|-------|--------------|--------------| | Enterprise | 90% | ESF + Network Extension (Alpha) | Full enforcement | | Network Only | 50% | pf + root | Network only, file observation | | Monitor Only | 25% | None | Observation only | | Minimal | 10% | None | Command logging only | **Current implementation status:** - Endpoint Security Framework: **Implemented** (Alpha — file and process monitoring via AUTH/NOTIFY events) - Network Extension: **Implemented** (FilterDataProvider + DNSProxyProvider) - sandbox-exec: **Implemented** (SBPL-based process sandboxing, deprecated but functional) - FSEvents fallback: **Observation only** (used when sysext is not installed) **ESF+NE Enterprise Mode (Alpha):** When running with ESF entitlements (requires Apple approval) and Network Extension (standard capability), agentsh provides near-Linux-level enforcement: - ESF (Endpoint Security Framework) intercepts file and process events with AUTH mode blocking - Network Extension (FilterDataProvider + DNSProxyProvider) enforces network and DNS policies - XPC bridge connects the System Extension to the Go policy engine - Session tracking maps processes to agentsh sessions for policy scoping See [macOS ESF+NE Architecture](docs/macos-esf-ne-architecture.md) for deployment details. **sandbox-exec Process Sandboxing:** For non-enterprise deployments, agentsh uses macOS's `sandbox-exec` command with SBPL (Sandbox Profile Language) profiles to provide minimal process isolation: | Feature | Description | |---------|-------------| | Default policy | Deny-all (`(deny default)`) with explicit allows | | File access | Restricted to workspace and explicitly allowed paths | | Network access | Denied by default, enabled via `capabilities: ["network"]` | | System access | Read-only access to system libraries and frameworks | | Temporary files | Full access to `/tmp`, `/private/tmp`, `/var/folders` | | TTY/PTY access | Interactive terminal support for commands | | IPC operations | POSIX IPC allowed; Mach/XPC configurable via `sandbox.xpc` | **Default Readable Paths (Always Allowed):** | Category | Paths | |----------|-------| | System libraries | `/usr/lib`, `/System/Library`, `/Library/Frameworks`, `/private/var/db/dyld` | | System tools | `/usr/bin`, `/usr/sbin`, `/bin`, `/sbin`, `/usr/local/bin` | | Homebrew | `/opt/homebrew/bin`, `/opt/homebrew/Cellar` | | Shared resources | `/usr/share` | | Device nodes | `/dev/null`, `/dev/random`, `/dev/urandom`, `/dev/zero` | **Configuration Options:** ```yaml sandbox: # Primary workspace - full read/write access workspace: /path/to/workspace # Additional paths to allow (full access) allowed_paths: - /home/user/.config/myapp - /usr/local/share/data # Capabilities to enable capabilities: - network # Enables network access (network*) ``` **SBPL Profile Structure:** The generated profile follows this structure: 1. `(deny default)` - Start with deny-all 2. Allow process operations (fork, exec, self-signal) 3. Allow sysctl reads for system info 4. Allow reading system paths (libraries, frameworks, tools) 5. Allow TTY/PTY access for interactive commands 6. Allow temp file operations 7. Allow workspace full access (from config) 8. Allow additional paths (from config) 9. Conditionally allow network (if `network` capability set) 10. Allow Mach and POSIX IPC for inter-process communication 11. Apply mach-lookup restrictions (if `sandbox.xpc.enabled`) **sandbox-exec Limitations:** - `sandbox-exec` is deprecated by Apple but still functional on all macOS versions - Provides file and network restrictions only (no process namespace isolation) - Cannot enforce resource limits (CPU, memory) - Cannot filter syscalls (unlike Linux seccomp-bpf) - Profile is passed inline via `-p` flag - No cgroup equivalent for resource accounting - Child processes inherit the sandbox (escape via fork not possible, but no PID namespace isolation) **XPC/Mach IPC Control:** When `sandbox.xpc.enabled: true`, agentsh restricts which XPC/Mach services sandboxed processes can connect to. This prevents: - Data exfiltration via clipboard (`com.apple.pasteboard.1`) - Privilege escalation via auth dialogs (`com.apple.security.authhost`) - TCC bypass attempts (`com.apple.tccd.*`) - AppleScript execution (`com.apple.coreservices.appleevents`) - Accessibility API abuse (`com.apple.accessibility.*`) Configuration: ```yaml sandbox: xpc: enabled: true mode: enforce # enforce | audit | disabled mach_services: default_action: deny # deny (allowlist) | allow (blocklist) allow: - "com.apple.system.logger" - "com.apple.CoreServices.coreservicesd" block_prefixes: - "com.apple.accessibility." ``` Default allow list includes essential services: system logger, CoreServices, launch services, SecurityServer, and cfprefsd. See [macOS XPC Sandbox](docs/macos-xpc-sandbox.md) for full documentation. **Recommendations for macOS deployments:** - **ESF+NE (Alpha):** Install via `brew tap canyonroad/tap && brew install --cask agentsh` for full enforcement - Use containers (Docker/Podman) with Linux or Lima VM for production workloads - Without the system extension, macOS operates in observation-only mode - Do not rely on network policy enforcement without ESF+NE - Consider the security score when evaluating risk ### macOS + Lima VM For production macOS deployments requiring full Linux-level security, agentsh supports Lima VM mode. When Lima is detected (running VM via `limactl`), agentsh automatically delegates operations to the Linux environment inside the VM: | Component | macOS Native | macOS + Lima | Impact | |-----------|--------------|--------------|--------| | File blocking | ESF (sysext) | FUSE3 in VM | ✅ **Full enforcement** | | Network blocking | pf (limited) | iptables DNAT | ✅ **Full enforcement** | | Process isolation | None | Linux namespaces | ✅ **Full isolation** | | Resource limits | None | cgroups v2 | ✅ **Full enforcement** | | Syscall filtering | None | seccomp-bpf | ✅ **Available** | **Lima Implementation Details:** | Feature | Implementation | |---------|----------------| | Resource limits | cgroups v2 at `/sys/fs/cgroup/agentsh/` | | CPU limits | `cpu.max` (quota/period in microseconds) | | Memory limits | `memory.max` (bytes) | | Process limits | `pids.max` | | Disk I/O limits | `io.max` (rbps/wbps per device) | | Network interception | iptables DNAT via `AGENTSH` chain | | TCP redirect | All outbound TCP (except localhost) to proxy port | | DNS redirect | UDP port 53 to DNS proxy port | **Security Score:** 85% (Full Linux capabilities with slight VM overhead) **Recommendations for Lima deployments:** - Use Lima for production macOS environments requiring isolation - Lima automatically detected when `limactl` is installed with running VM - Force Lima mode via config: `platform.mode: darwin-lima` - VM overhead is ~200-500MB RAM with slightly slower file I/O via virtiofs ### Windows Windows now has **kernel-level enforcement** via a mini filter driver, providing near-Linux-level security: | Component | Linux | Windows | Impact | |-----------|-------|---------|--------| | File blocking | FUSE (enforced) | Mini filter driver | ✅ **Enforced** | | Network blocking | eBPF/iptables | WinDivert + WFP fallback | ✅ **Enforced** | | Registry blocking | N/A | CmRegisterCallbackEx | ✅ **Enforced** | | Process isolation | Namespaces | Driver session tracking | ✅ **Working** | | Resource limits | cgroups v2 | Job Objects | ✅ **Working** | | Process tracking | ptrace/wait | Driver + Job Objects | ✅ **Working** | **Driver Components:** | Component | Technology | Status | |-----------|------------|--------| | Filesystem | FltRegisterFilter (Mini Filter) | ✅ **Enforced** - Create, write, delete, rename | | Filesystem (alt) | WinFsp (cgofuse) | ✅ **Enforced** - FUSE-style mounting with soft-delete | | Network | WinDivert (transparent proxy) | ✅ **Enforced** - TCP/DNS interception | | Network fallback | WFP (Windows Filtering Platform) | ✅ **Block-only mode** | | Registry | CmRegisterCallbackEx | ✅ **Enforced** - All operations | | Process | PsSetCreateProcessNotifyRoutineEx | ✅ **Tracking** - Session association | **Registry Security Features:** The driver provides comprehensive registry protection: - **Operation interception:** Query, set, delete, create, rename keys and values - **Policy enforcement:** Allow, deny, or require approval based on registry rules - **High-risk path detection:** Automatic detection and blocking of persistence/security paths - **MITRE ATT&CK mapping:** Events include technique IDs for security monitoring | High-Risk Path | Risk | MITRE Technique | Default | |----------------|------|-----------------|---------| | `HKLM\...\CurrentVersion\Run*` | Critical | T1547.001 - Registry Run Keys | **Deny** | | `HKLM\...\Winlogon*` | Critical | T1547.004 - Winlogon Helper DLL | **Deny** | | `HKLM\SYSTEM\...\Services\*` | High | T1543.003 - Windows Service | **Approve** | | `HKLM\...\Windows Defender\*` | Critical | T1562.001 - Disable Security Tools | **Deny** | | `HKLM\...\Control\Lsa\*` | Critical | T1003 - Credential Dumping | **Deny** | | `HKLM\...\Image File Execution Options\*` | Critical | T1546.012 - IFEO Injection | **Deny** | | `HKLM\...\KnownDLLs\*` | Critical | T1574.001 - DLL Search Order Hijacking | **Deny** | **Driver Fail Modes:** | Mode | Behavior | Use Case | |------|----------|----------| | `FAIL_MODE_OPEN` | Allow on service unavailable | Development, availability-first | | `FAIL_MODE_CLOSED` | Deny on service unavailable | Production, security-first | **Deployment Requirements:** | Environment | Signing Requirement | |-------------|---------------------| | Development | Test signing (`bcdedit /set testsigning on`) | | Production | EV code signing + Microsoft attestation | | Enterprise | WHQL certification (optional, recommended) | **Current implementation status:** - Mini filter driver: ✅ **Enforced** (file create, write, delete, rename) - WinFsp filesystem: ✅ **Enforced** (FUSE-style mounting via cgofuse, soft-delete support) - WinDivert network: ✅ **Enforced** (TCP proxy, DNS interception) - WFP fallback: ✅ **Block-only** (when WinDivert unavailable) - Registry blocking: ✅ **Enforced** (all operations with high-risk protection) - Process tracking: ✅ **Working** (driver-based session association) - Policy caching: ✅ **Working** (configurable TTL, per-rule override) - AppContainer sandbox: ✅ **Enforced** (process isolation with output capture) **Recommendations for Windows deployments:** - Use the mini filter driver for production deployments - Enable `FAIL_MODE_CLOSED` for high-security environments - Review registry policy rules - high-risk paths are blocked by default - Monitor fail mode transitions in SIEM - EV code signing required for production (no test signing) - Consider WHQL certification for enterprise deployment - WinFsp provides an alternative FUSE-style filesystem with soft-delete capabilities **WinFsp Filesystem Mounting:** WinFsp provides FUSE-style filesystem mounting on Windows using the shared `internal/platform/fuse/` package (cgofuse). This offers: | Feature | Description | |---------|-------------| | Cross-platform code | Same FUSE implementation works on Linux (FUSE3) and Windows (WinFsp) | | Soft-delete | Files moved to trash instead of permanent deletion | | Policy enforcement | Same policy engine as minifilter with file operation checks | | Minifilter coexistence | Process exclusion prevents double-interception when both are active | **Requirements:** - WinFsp installed: `winget install WinFsp.WinFsp` - CGO enabled build: `CGO_ENABLED=1 go build` **Double-interception prevention:** When both minifilter and WinFsp are active, the Go client calls `ExcludeSelf()` before mounting to tell the minifilter to skip file operations from the agentsh process, preventing duplicate event capture. **AppContainer Sandbox Isolation:** Windows 8+ supports AppContainer, a kernel-enforced capability isolation mechanism. agentsh uses AppContainer as the primary process isolation layer, with the minifilter driver providing defense-in-depth: | Layer | Technology | Purpose | |-------|------------|---------| | Primary | AppContainer | Kernel-enforced capability isolation | | Secondary | Minifilter driver | Policy-based file/registry rules | **How It Works:** When agentsh executes a command in a sandboxed session, it: 1. Creates an AppContainer profile with a unique SID via `CreateAppContainerProfile` 2. Grants the container SID access to the workspace (read/write) via ACL modification 3. Grants the container SID access to system directories (read/execute) 4. Optionally adds network capability SIDs (internetClient, privateNetwork) 5. Spawns the process inside the container with extended startup info 6. Captures stdout/stderr via inheritable pipes 7. Cleans up ACLs (using `REVOKE_ACCESS` mode) and deletes the profile when done **AppContainer Features:** | Feature | Description | |---------|-------------| | Capability isolation | Kernel-level enforcement of allowed capabilities | | Registry isolation | Automatic isolation of registry access | | Network control | Configurable network access levels | | ACL granting | Explicit path access required for file system access | | Output capture | Full stdout/stderr capture from sandboxed processes | | ACL cleanup | Automatic removal of granted ACLs on sandbox close | **Network Access Levels:** | Level | Capability SIDs | Use Case | |-------|-----------------|----------| | `NetworkNone` | None | Maximum isolation (default) | | `NetworkOutbound` | S-1-15-3-1 (internetClient) | Outbound connections only | | `NetworkLocal` | S-1-15-3-3 (privateNetwork) | Private network only | | `NetworkFull` | Both SIDs | Full network access | **Configuration Options:** ```go WindowsSandboxOptions{ UseAppContainer: true, // Enable AppContainer (default) UseMinifilter: true, // Enable minifilter policy (default) NetworkAccess: NetworkNone, // Network level (default: none) FailOnAppContainerError: true, // Fail hard on setup error (default) } ``` **Isolation Level:** Windows reports `IsolationPartial` when AppContainer is available (capability-based, not namespace-based like Linux). **AppContainer Limitations:** - Requires Windows 8+ (version 6.2+) - Capability-based, not namespace-based (sandboxed processes see all system processes) - Cannot enforce resource limits (use Job Objects via minifilter for that) - Cannot filter syscalls (no equivalent to Linux seccomp) - Requires modifying filesystem ACLs for path access - Profile names must not contain special characters (sanitized automatically) **Recommendations for Windows sandboxed execution:** - Enable AppContainer for process isolation (`UseAppContainer: true`) - Combine with minifilter for comprehensive policy enforcement - Use `NetworkNone` for commands that don't need network access - Set `FailOnAppContainerError: true` in high-security environments - Consider WSL2 mode for full Linux-level isolation **Implementation:** See `internal/platform/windows/sandbox.go` and `internal/platform/windows/appcontainer.go`. See [Windows Driver Deployment Guide](docs/windows-driver-deployment.md) for installation and configuration. ### Windows WSL2 For Windows deployments requiring full Linux-level security, agentsh supports WSL2 mode. WSL2 runs a real Linux kernel, providing full Linux capabilities: | Component | Windows Native | Windows WSL2 | Impact | |-----------|----------------|--------------|--------| | File blocking | Mini Filter | FUSE3 in VM | ✅ **Full enforcement** | | Network blocking | WinDivert | iptables DNAT | ✅ **Full enforcement** | | Process isolation | AppContainer | Linux namespaces | ✅ **Full isolation** | | Resource limits | Job Objects | cgroups v2 | ✅ **Full enforcement** | | Syscall filtering | None | seccomp-bpf | ✅ **Available** | | Registry monitoring | Mini Filter | N/A | ❌ Not available | **WSL2 Implementation Details:** | Feature | Implementation | |---------|----------------| | Resource limits | cgroups v2 at `/sys/fs/cgroup/agentsh/` | | CPU limits | `cpu.max` (quota/period in microseconds) | | Memory limits | `memory.max` (bytes) | | Process limits | `pids.max` | | Disk I/O limits | `io.max` (rbps/wbps per device) | | Network interception | iptables DNAT via `AGENTSH` chain | | TCP redirect | All outbound TCP (except localhost) to proxy port | | DNS redirect | UDP port 53 to DNS proxy port | **Security Score:** 100% (Full Linux capabilities inside VM) **Trade-offs vs Windows Native:** - ✅ Full Linux security features (namespaces, seccomp, cgroups) - ✅ Better isolation than AppContainer - ❌ No Windows registry monitoring - ❌ Slight VM overhead - ❌ File I/O to Windows drives (`/mnt/c/`) slower than native **Recommendations for WSL2 deployments:** - Use WSL2 for maximum security on Windows - Keep workspaces on Linux filesystem (`/home/...`) for best performance - Install WSL2 with: `wsl --install -d Ubuntu` - agentsh auto-detects WSL2 when running inside the VM ## Security Defaults | Component | Default | |-----------|---------| | File access | Deny (unless explicitly allowed) | | Network access | Deny (unless explicitly allowed) | | Command execution | Deny (unless explicitly allowed) | | Unix sockets | Deny (unless explicitly allowed) | | Signal delivery | Allow to self/children, deny to external/system (Linux only) | | Environment variables | Allow (unless in deny list or explicit allow-list defined) | | Approval timeout | Deny | ## Reporting Security Issues If you discover a security vulnerability in agentsh: 1. **Do not** open a public GitHub issue 2. Email security concerns to the maintainers privately 3. Include: - Description of the vulnerability - Steps to reproduce - Potential impact - Suggested fix (if any) We aim to respond within 48 hours and will coordinate disclosure timing with you. ## Security Checklist for Operators Before deploying agentsh in production: - [ ] Review and customize the default policy for your use case - [ ] Ensure policy files are not writable by the agent user - [ ] Enable audit logging and monitor for policy violations - [ ] Set appropriate resource limits for your workload - [ ] Use CIDR rules (not just domains) for critical network blocks - [ ] Test approval workflows to ensure timeouts result in deny - [ ] Run agentsh as a non-root user - [ ] Keep agentsh updated for security fixes - [ ] Configure DLP patterns for organization-specific sensitive data - [ ] Enable network rules to force LLM traffic through the proxy - [ ] Review LLM usage reports for unexpected token consumption - [ ] Enable checkpoint/rollback for sessions running destructive commands - [ ] Configure auto-checkpoint triggers appropriate for your workload - [ ] For audit integrity, consider using external KMS (AWS/Azure/Vault/GCP) instead of local key files ## Changelog | Date | Change | |------|--------| | 2026-05-06 | v0.19.2: shim's kernelinstall path skips wrap-init when an ancestor's seccomp filter is already inherited (`/proc/self/status` `Seccomp_filters:`), avoiding nested-stacking failures masked as `ECANCELED` on Runloop devboxes (#282). Wrap-init now appends `dirname(AgentCommand)` to Landlock `allow_execute` (#283). `agentsh-unixwrap` resolves the command path before installing the seccomp filter so `exec.LookPath` probes are not intercepted by the file-monitor handler (#283 bug B). Seccomp install raw kernel errnos are surfaced via `SCMP_FLTATR_API_SYSRAWRC`; `WAIT_KILLABLE_RECV` retry is gated on `EINVAL` (#285). | | 2026-03-04 | Added execve hardening: path canonicalization via EvalSymlinks and transparent command unwrapping with dual evaluation | | 2026-02-13 | Added configurable deferred FUSE mounting for snapshot-restore environments | | 2026-01-11 | Added signal interception via seccomp user-notify for policy-based signal control (Linux) | | 2026-01-07 | Added external KMS integration for audit integrity keys (AWS KMS, Azure Key Vault, HashiCorp Vault, GCP Cloud KMS) | | 2026-01-07 | Added checkpoint/rollback for workspace state recovery with auto-checkpoint triggers | | 2026-01-03 | Wired up unix socket enforcement via seccomp user-notify (Linux only) | | 2026-01-03 | Implemented macOS sandbox-exec wrapper with SBPL profiles | | 2026-01-03 | Implemented FUSE event emission for file operation monitoring | | 2026-01-03 | Implemented Lima and WSL2 Linux namespace isolation via unshare | | 2026-01-03 | Implemented Lima and WSL2 bindfs-based filesystem mounting inside VMs | | 2026-01-03 | Implemented WSL2 cgroups v2 resource limits and iptables network interception | | 2026-01-03 | Implemented Lima VM cgroups v2 resource limits and iptables network interception | | 2026-01-02 | Added embedded LLM proxy with DLP redaction and usage tracking | | 2026-01-02 | Implemented AppContainer sandbox execution with stdout/stderr capture | | 2026-01-02 | Added ACL cleanup on AppContainer sandbox close | | 2026-01-02 | Added WinFsp filesystem mounting with shared fuse package for Windows | | 2026-01-02 | Added minifilter process exclusion for WinFsp coexistence | | 2026-01-01 | Implemented macOS ESF+NE for enterprise-tier enforcement (90% security score) | | 2026-01-01 | Added XPC bridge for System Extension ↔ Go policy engine communication | | 2026-01-01 | Added session tracking for process-to-session mapping on macOS | | 2025-12-31 | Implemented FUSE-T mounting for macOS file policy enforcement | | 2025-01-01 | Added LD_PRELOAD and code injection env vars to deny list | | 2025-01-01 | Fixed eBPF race condition with ptrace-stopped start | | 2025-01-01 | Added full-path and glob matching for commands | | 2025-01-01 | Changed command default from allow to deny |