This document describes the threat model, security mechanisms, and known limitations of agentsh.
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.
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 |
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 |
┌─────────────────────────────────────────────────────────────┐
│ 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)
- 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.
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/fuseis gated behind a readiness marker - Any setup where FUSE availability is delayed relative to session creation
Configuration:
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,ensureFUSEMountchecks 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_commandis configured, runs the command (gated bydeferred_marker_fileif set) - On success, mounts the FUSE overlay and emits a
fuse_mountedevent with"deferred": true - On failure, emits
fuse_mount_failedand 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_commandis empty, no automatic enable is attempted — FUSE must become available through external means.
- 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.
- Pre-execution policy check on command + arguments
- Three matching modes:
- Basename:
shmatches any path ending in/sh - Full path:
/bin/shmatches only that exact path - Glob pattern:
/usr/*/python3matches/usr/bin/python3,/usr/local/python3
- Basename:
- Args pattern matching for dangerous flag combinations
- Path canonicalization:
filepath.EvalSymlinksresolves symlinks before policy evaluation, preventing bypass via symlinks or/proc/self/rootpaths (relative path resolution is applied forexecveatcalls) - 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.
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_SEIZEto attach without stopping the target process - Intercepts
execve(2)andexecveat(2)syscalls at entry - Reads filename and argv from tracee process memory via
/proc/<tid>/mem - Evaluates the same policy rules as seccomp mode
- Deny: sets syscall number to -1 (invalid), then fixes up return value with
-EACCESon 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
execveatwithAT_EMPTY_PATH(fd-based exec) is intercepted alongside regularexecve- 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_PTRACEcapability (Linux-only)
Configuration: See Security Modes - Ptrace Configuration.
- 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
- Linux:
- 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.
sandbox:
env_inject:
BASH_ENV: "/usr/lib/agentsh/bash_startup.sh"Security properties:
env_injectvalues bypass the deny list (operator explicitly wants them)- Policy-level
env_injectoverrides global config (for per-policy customization) - Trust boundary: config file access (not user-controllable)
- Memory limits (with swap disabled)
- CPU quota
- Process count limits
- Command and session timeouts
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_NOTIFto 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 for configuration examples.
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 for detailed configuration.
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:
# Create manual checkpoint
agentsh checkpoint create --session <id> --workspace /path
# List checkpoints
agentsh checkpoint list --session <id>
# Show checkpoint details and diff
agentsh checkpoint show <cp-id> --session <id> --workspace /path --diff
# Preview rollback (dry-run)
agentsh checkpoint rollback <cp-id> --session <id> --workspace /path --dry-run
# Perform rollback
agentsh checkpoint rollback <cp-id> --session <id> --workspace /path
# Purge old checkpoints
agentsh checkpoint purge --session <id> --older-than 24h --keep 10Auto-Checkpoint Configuration:
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 daysDefault 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
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:
# 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.encAuthentication:
- 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
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:
agentrole: Can execute commands, cannot approveapproverrole: Can view and resolve approval requestsadminrole: Full access including policy management
# 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"]agentsh provides comprehensive security controls for Model Context Protocol (MCP) tool invocations:
Policy-based control over which MCP tools can be invoked:
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 |
Detect and optionally block MCP tool definition changes (rug pull detection):
sandbox:
mcp:
version_pinning:
enabled: true
on_change: block # block, alert, allow
auto_trust_first: trueCLI management:
agentsh mcp pins list
agentsh mcp pins trust --server github --tool create_issue --hash sha256:...
agentsh mcp pins reset --server github --tool create_issueToken bucket rate limiting for MCP calls and network requests:
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: 10agentsh 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-keyoranthropic-versionheaders - 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 for configuration and usage details.
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.
Network rules based on domain names resolve DNS at connection time. An attacker controlling DNS could potentially:
- Resolve
evil.comto an allowed IP during policy check - 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.
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.
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.
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.
macOS has significantly reduced security enforcement compared to Linux due to platform limitations:
| Component | Linux | macOS | Impact |
|---|---|---|---|
| File blocking | FUSE (enforced) | FUSE-T (enforced with CGO) | Enforced when built with CGO |
| 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 | 95% | ESF (Apple approval) + Network Extension | Full enforcement |
| Full | 75% | FUSE-T + root | File + network blocking |
| Network Only | 50% | pf + root | Network only, file observation |
| Monitor Only | 25% | None | Observation only |
| Minimal | 10% | None | Command logging only |
Entitlement requirements:
- ESF (Endpoint Security): Requires Apple approval - submit business justification via Developer Portal
- Network Extension: Standard capability since November 2016 - enable in Xcode, no Apple approval needed
Current implementation status:
- FUSE-T mounting: Implemented (requires CGO + FUSE-T:
brew install fuse-t) - FSEvents fallback: Observation only (cannot block, used when CGO unavailable)
- pf network rules: Loopback only (real interfaces not intercepted)
- Endpoint Security Framework: Implemented (requires Apple approval for ESF entitlement)
- Network Extension: Implemented (standard capability - no Apple approval needed)
- sandbox-exec: Implemented (SBPL-based process sandboxing, deprecated but functional)
ESF+NE Enterprise Mode:
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 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:
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:
(deny default)- Start with deny-all- Allow process operations (fork, exec, self-signal)
- Allow sysctl reads for system info
- Allow reading system paths (libraries, frameworks, tools)
- Allow TTY/PTY access for interactive commands
- Allow temp file operations
- Allow workspace full access (from config)
- Allow additional paths (from config)
- Conditionally allow network (if
networkcapability set) - Allow Mach and POSIX IPC for inter-process communication
- Apply mach-lookup restrictions (if
sandbox.xpc.enabled)
sandbox-exec Limitations:
sandbox-execis 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
-pflag - 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:
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 for full documentation.
Recommendations for macOS deployments:
- Enterprise: Use ESF+NE mode for full enforcement (ESF requires Apple approval; NE is standard capability)
- Standard: Install FUSE-T (
brew install fuse-t) for file policy enforcement - Build with CGO enabled for FUSE-T support:
CGO_ENABLED=1 go build - ESF+NE mode automatically falls back to FUSE-T if entitlements are unavailable
- Use containers (Docker/Podman) with Linux for full enforcement if entitlements unavailable
- Without FUSE-T or ESF, treat macOS as audit/observation mode only
- Do not rely on network policy enforcement without ESF+NE or pf configuration
- Consider the security score when evaluating risk
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 | FUSE-T | 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/<session> |
| 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
limactlis 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 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_CLOSEDfor 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 macOS (FUSE-T) 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:
- Creates an AppContainer profile with a unique SID via
CreateAppContainerProfile - Grants the container SID access to the workspace (read/write) via ACL modification
- Grants the container SID access to system directories (read/execute)
- Optionally adds network capability SIDs (internetClient, privateNetwork)
- Spawns the process inside the container with extended startup info
- Captures stdout/stderr via inheritable pipes
- Cleans up ACLs (using
REVOKE_ACCESSmode) 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:
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
NetworkNonefor commands that don't need network access - Set
FailOnAppContainerError: truein 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 for installation and configuration.
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/<session> |
| 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
| 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 |
If you discover a security vulnerability in agentsh:
- Do not open a public GitHub issue
- Email security concerns to the maintainers privately
- 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.
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
| Date | Change |
|---|---|
| 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 |