Runtime sandboxing for AI coding agents
| Project | Aixgate |
| Repository | https://github.com/aixgo-dev/aixgate |
| Sibling project | Aixgo — production AI agent framework for Go |
| Author | Charles Green |
| Current release | v0.1.0 (see GitHub Releases for the canonical version) |
| Date | May 2026 |
| License | MIT |
- Executive Summary
- Problem Statement
- Goals and Non-Goals
- Users and Use Cases
- Product Overview
- Architecture
- Policy Specification
- Audit Log
- Packaging and Distribution
- Relationship to aixgo.dev
- Roadmap
- Success Metrics
- Risks and Open Questions
- Implementation Notes for Contributors
- v0.1 Weekend Build Plan
- Appendix
Aixgate is a vendor-agnostic runtime sandbox for AI coding agents (Claude Code, Cursor, Aider, OpenAI Codex agents, and any other process that reads and writes files on behalf of an LLM). It enforces deny-by-default filesystem access policies at the OS boundary, ensuring that sensitive files such as .env, cloud credentials, SSH private keys, and personal documents are never exposed to an agent unless an explicit policy rule permits it.
Aixgate is an open-source component of aixgo.dev, the production-grade Go framework for AI agents. Where aixgo provides the primitives to build agents, Aixgate provides the primitives to run them safely on developer workstations. It is written in Go, distributed as a single binary, supports both macOS and Linux, and integrates into existing developer workflows by launching agents inside a transparent filesystem overlay.
The core hypothesis is simple: developers are adopting agentic coding tools faster than they are adopting the security controls to govern them. Today, running an AI agent in a project directory is roughly equivalent to running an untrusted script with full access to the user's home directory. Aixgate closes that gap without requiring behavioral change from the developer or cooperation from the agent vendor.
- A developer can launch any AI coding agent with a single
aixgate runcommand and be confident their.envfiles, credentials, and SSH keys are not accessible to that agent. - Policy is declarative, portable across agents, and version-controllable alongside a project repository.
- Every filesystem access decision is logged to a structured audit trail that can be reviewed, searched, and shipped to a SIEM if desired.
- Installation and day-one experience are smooth enough that a developer will actually use Aixgate instead of bypassing it.
AI coding agents execute with the full privileges of the user running them. In a typical developer setup, this means:
- Unrestricted read access to the home directory, including
.envfiles,~/.aws/credentials,~/.ssh/, browser-saved passwords, and personal documents. - Unrestricted shell execution, allowing the agent to
curl,scp, or otherwise exfiltrate anything it can read. - Unrestricted write access to project files and system configuration.
This is acceptable when the agent is a trusted local tool operating on intentional input. It is not acceptable when:
- The agent receives input from untrusted sources (a pasted error message, a GitHub issue, a webpage it was asked to summarize) — the well-documented prompt injection attack surface.
- The agent operates autonomously for extended periods, with reduced human oversight of each action.
- The developer is operating under a compliance regime (SOC 2, ISO 27001, financial regulation) that requires access controls over sensitive data.
| Tool category | What it does | Why it is insufficient |
|---|---|---|
| Aqua / Falco / Tetragon | Runtime protection for containers and Kubernetes workloads | Targets server environments, not developer laptops. No macOS support. Requires privileged kernel access. |
| macOS App Sandbox | Apple's built-in sandboxing for App Store apps | Not available to arbitrary developer tools. Configuration is not portable. |
| Docker Desktop containers | Isolate agents in containers | Heavy, breaks developer workflow, agents cannot access project source as they expect, no fine-grained policy. |
| Agent-specific permission prompts | e.g. Claude Code's tool approval flow | Vendor-specific, inconsistent, bypassable, and the user quickly clicks through. |
| Vendor MCP servers with allowlists | Some agents let you allowlist tools | Only works within that vendor's tool-calling flow. An agent that shells out bypasses it entirely. |
The primary target user for v1 is the individual developer or small team running AI coding agents on a personal or work laptop. Within that audience:
- Security-conscious individual developers who want a belt-and-braces layer on top of vendor permission prompts.
- Engineering teams at security-sensitive companies (fintech, healthcare, infrastructure) that want to adopt agentic tooling but need a defensible answer to "how are you protecting customer data and production credentials?"
- Consultants and contractors, like the author, who run agents across multiple client codebases and need strong guarantees that credentials from one client are not accessible during a session scoped to another.
- G1. Vendor agnostic. Aixgate works with any AI agent that runs as a local process, without requiring cooperation from the agent vendor.
- G2. Deny by default. Access to files and commands is denied unless explicitly permitted by the active policy.
- G3. Transparent. Agents see a filtered filesystem view and shell environment; they do not know they are sandboxed. No agent code changes required.
- G4. Cross-platform. macOS (Apple Silicon and Intel) and Linux (x86_64 and arm64) are first-class. No Windows support in v1.
- G5. Low friction. A developer already using Claude Code can adopt Aixgate without changing how they work beyond prefixing
aixgate run. - G6. Auditable. Every access decision is logged as structured data that can be reviewed or forwarded to a SIEM.
- G7. Open source. Permissively licensed (MIT), contribution-friendly, part of the aixgo.dev ecosystem.
- G8. Single binary. Install, upgrade, and uninstall must each be a single command.
- Windows support. Viable v2; v1 focuses on macOS and Linux where AI agent adoption is concentrated.
- Kubernetes or CI sandboxing. Aixgate is designed for local developer use. Server-side enforcement is a future aixgo product.
- Network egress control. Out of scope for v1. We do not intercept outbound connections. A future version may add optional network policy via a local proxy.
- Replacing agent vendor permission flows. Aixgate is a defense-in-depth layer; it does not tell users to disable Claude Code's built-in approvals.
- Kernel-level enforcement. v1 uses FUSE and OS-provided process isolation. eBPF and LSM-based enforcement are explicit v2+ territory.
- Policy marketplace or GUI. v1 ships sensible defaults and YAML policies. A web UI or shared policy registry is a later concern.
Aixgate will not attempt to sandbox agents that are running as root, nor will it claim to defend against a motivated attacker with local code execution. The threat model is an agent acting on behalf of the user that may misbehave due to prompt injection, a flawed plan, or a buggy tool use — not an attacker who has already fully compromised the machine.
Runs Claude Code on a personal laptop across side projects and contract work. Has had at least one close call where an agent attempted to read a .env or called a destructive command. Wants an always-on guardrail without giving up the productivity of agentic tools.
Works across several client codebases in a given week. Each client has its own credentials, API keys, and sensitive data. Needs hard boundaries so that a session in Client A's repo cannot see Client B's .env files, regardless of how "helpful" the agent tries to be.
Responsible for approving AI coding agent use across a 50- to 500-person engineering team. Needs a defensible story for the security and compliance teams: centralized policy, audit logs, and provable boundaries. Cares deeply about reproducibility and CI integration in the long run.
cd ~/code/client-a/app
aixgate run --profile claude-code -- claudeThe agent launches inside a sandbox where only ~/code/client-a/app is readable and writable, plus a small set of system paths required for tooling. The user's home directory, other clients' projects, SSH keys, AWS credentials, and personal documents return as if they do not exist.
A project repository contains a .aixgate.yaml file declaring which files the agent may access and which commands it may run. When aixgate run is invoked inside that project, the policy is loaded automatically. The policy is checked into version control and code-reviewed.
aixgate audit tail
aixgate audit query --since 24h --denied-onlyThe developer can at any time review every read, write, and exec decision Aixgate made. A security team can ship these logs to a SIEM for monitoring.
Out of the box, Aixgate ships with profiles for popular agents (Claude Code, Aider, Cursor headless, generic). Each profile encodes the minimum access that agent needs to function, which users can tighten or loosen as desired.
Aixgate launches the target agent as a child process inside a filesystem namespace (Linux) or sandbox profile (macOS) that presents a FUSE overlay of the real filesystem. The overlay consults the active policy for every read, write, and lookup operation. Allowed paths pass through transparently. Denied paths return ENOENT, making them invisible to the agent. Sensitive paths can optionally return redacted stubs. Every decision is written to a structured audit log. The agent cannot escape this boundary without subverting the OS process isolation primitives Aixgate builds on.
aixgate run [--profile NAME] [--policy FILE] -- CMD [ARGS...]Launches a command inside a sandbox. Policy is resolved in order: explicit --policy flag, project-local .aixgate.yaml, named profile, built-in default.
aixgate initCreates a .aixgate.yaml in the current directory with safe starter defaults for the detected project type.
aixgate policy check [FILE]Validates policy syntax and reports any unresolvable globs or unsafe rules (such as overly broad allowlists).
aixgate policy explain PATHFor a given file path, explains what the active policy would do: allow, deny, redact, or prompt.
aixgate audit tail [--follow] [--profile NAME]
aixgate audit query --since 24h [--denied-only] [--path GLOB]Tail or search the audit log.
aixgate profile list
aixgate profile show NAMEInspect available built-in and user profiles.
aixgate doctorDiagnostic command that verifies FUSE is installed, permissions are correct, and the sandbox can be established. Outputs a remediation checklist for common setup issues.
Aixgate is a single Go binary composed of the following internal components:
| Component | Responsibility |
|---|---|
CLI (cmd/aixgate) |
Argument parsing, user-facing commands, orchestration. |
Policy engine (internal/policy) |
Load, validate, and evaluate policies. Returns allow / deny / redact / prompt decisions for a given access request. |
Overlay filesystem (internal/fs) |
FUSE-based filesystem that mediates every syscall through the policy engine. Implements path canonicalization, redaction stubs, and ENOENT masking. |
Process sandbox (internal/aixgate/sandbox) |
Platform-specific process isolation: mount namespaces and landlock on Linux, sandbox-exec on macOS. Responsible for chroot, environment stripping, and PATH restriction. |
Audit log (internal/audit) |
Structured JSONL writer with rotation. Supports live tailing and query. |
Profile registry (internal/profiles) |
Built-in profiles shipped with the binary, plus user profile discovery in ~/.aixgate/profiles. |
Prompt daemon (internal/prompt, v1.1) |
Desktop notifications for interactive allow/deny prompts when policy specifies prompt on deny. |
aixgate/
├── cmd/
│ └── aixgate/ # CLI entry point
│ └── main.go
├── internal/
│ ├── policy/ # Parse + evaluate policies
│ │ ├── schema.go # Policy struct, YAML tags
│ │ ├── loader.go # Load, merge, extend
│ │ ├── matcher.go # Glob + rule evaluation
│ │ ├── matcher_test.go
│ │ └── rego.go # Optional OPA integration (v2)
│ ├── fs/ # FUSE filesystem (Linux only)
│ │ ├── overlay.go # Core overlay logic (hanwen/go-fuse, pure Go)
│ │ ├── redact.go # Stub/redaction generation
│ │ ├── canonical.go # Path canonicalization
│ │ └── linux.go # Linux-specific FUSE setup
│ ├── sandbox/ # Process isolation (pure-Go, no cgo)
│ │ ├── sandbox.go # Cross-platform Sandbox interface
│ │ ├── policy.go # Policy struct + DefaultV01Policy
│ │ ├── linux.go # go-fuse overlay + go-landlock + go-seccomp-bpf
│ │ └── darwin.go # sandbox-exec profile generation + exec.Command
│ ├── audit/ # Structured logging
│ │ ├── writer.go # JSONL writer with rotation
│ │ ├── query.go # Query + tail
│ │ └── schema.go
│ ├── profiles/ # Profile registry
│ │ ├── registry.go
│ │ └── builtin/ # Embedded default profiles
│ │ ├── claude-code.yaml
│ │ ├── aider.yaml
│ │ ├── cursor.yaml
│ │ └── generic.yaml
│ ├── proc/ # Process lifecycle, signals
│ │ └── supervisor.go
│ └── prompt/ # Desktop prompts (v1.1)
│ ├── prompt.go
│ ├── darwin.go # osascript
│ └── linux.go # notify-send
├── pkg/ # Public Go API (for aixgo integration)
│ └── aixgate/
│ └── client.go
├── profiles/ # Shipped example profiles (not embedded)
├── docs/
├── scripts/
├── test/
│ └── e2e/ # End-to-end tests with real agents
├── .github/
│ └── workflows/
├── go.mod
├── go.sum
├── Makefile
├── LICENSE # MIT
├── CLAUDE.md # Instructions for Claude Code contributors
└── README.md
Aixgate is pure Go. No cgo, no C toolchain, no macFUSE kext. Enforcement is delivered per platform by composing pure-Go libraries (on Linux) and host-provided binaries invoked via exec.Command (on macOS), behind a single Sandbox interface.
- A mount namespace (
unshare(CLONE_NEWNS)) is created for the agent process. - A FUSE filesystem is mounted inside the namespace at the agent's perceived root, backed by
hanwen/go-fuse(pure Go, no cgo). - Landlock is applied via
landlock-lsm/go-landlock(Linux 5.13+, pure Go) as a belt-and-braces restriction even if the FUSE layer is somehow bypassed. seccomp-bpffilters installed viaelastic/go-seccomp-bpf(pure Go) blockptrace,mount,bpf, and other escape vectors.- A restricted
PATHand a filtered environment are injected.
sandbox-execis the primary enforcement mechanism: Aixgate generates a.sbprofile from the policy ((allow file-read* (subpath "/foo"))/(deny file-read* (subpath "/foo/secrets"))), writes it to a temp file, and launches the agent viaexec.Command("sandbox-exec", "-f", profile, "--", cmd, args...). This is kernel-level TrustedBSD MACF enforcement with genuinely fine-grained path policy.sandbox-execis deprecated by Apple but ships in every macOS release through Sequoia (2026) and is used by Apple's own components (WebKit, xcrun). We accept the deprecation risk and document FUSE-T +hanwen/go-fuseas a fallback path if Apple ever removes it.- Audit events are captured by tailing
log stream --predicate 'subsystem == "com.apple.sandbox"'and translated into the Aixgate JSONL format. - The Aixgate binary is signed and notarized to avoid Gatekeeper friction, but requires no kernel extension approval.
For every filesystem operation the agent performs, Aixgate follows this sequence:
- Canonicalize the path, resolving symlinks and
..components against the real filesystem root. - Match the canonical path against the policy's explicit
denyrules. If matched, returnENOENT(for reads and lookups) orEACCES(for writes), and log the denial. - Match against
redactrules. If matched, return a synthesized stub instead of real contents. - Match against
allowrules. If matched, pass through to the real filesystem. - Otherwise, apply the default action (
denyfor v1). Log the decision.
Returning "permission denied" signals to the agent that a file exists but it cannot access it. Well-behaved agents may retry, prompt the user, or report an error that reveals the path. Returning "no such file or directory" gives the agent no information: it proceeds as if the file does not exist.
This choice is deliberate and important; it is why Aixgate is effective against agents that might otherwise try to work around an obstacle. Policies can opt into EACCES semantics per rule for cases where the developer wants visibility.
In scope:
- A benign agent that is tricked by prompt injection into attempting to read sensitive files.
- A buggy agent plan that inadvertently tries to touch sensitive files.
- An agent that attempts to
curlorscpcredentials out — Aixgate prevents the read; exfiltration is moot. - Forked subprocesses (
bash -c "cat .env") — the sandbox is inherited via process isolation, not FUSE alone.
Out of scope:
- An attacker with root privileges on the machine.
- An attacker with local code execution outside the Aixgate-launched process.
- Kernel-level exploits.
- Side-channel attacks (timing, filesystem metadata inference).
- Readable by humans. YAML, not Rego or CUE for v1. Rego may be added as an advanced-user option in v2.
- Portable. The same policy runs identically on macOS and Linux.
- Composable. Profiles can extend other profiles. Project policies can extend a profile.
- Explicit. No wildcarded inheritance; every effective rule can be traced to a source file and line.
profile: claude-code
extends: defaults/generic
default: deny
filesystem:
allow_read:
- ${PROJECT}/**
- ~/.config/git/**
- /usr/lib/**
- /opt/homebrew/**
allow_write:
- ${PROJECT}/**
- ${TMPDIR}/aixgate-*/**
redact:
- '**/.env'
- '**/.env.*'
- ~/.aws/credentials
deny:
- ~/.ssh/id_*
- ~/Documents/**
exec:
allow: [git, node, npm, pnpm, python3, go, make]
deny_args:
git: ['push --force', 'config --global']
env:
pass_through: [PATH, HOME, LANG, LC_ALL, TERM]
inject:
AIXGATE_ACTIVE: '1'
audit:
log: ~/.aixgate/audit.jsonl
on_deny: log # log | prompt | block_silentlyWhen a path matches multiple rules, precedence is:
explicit deny > redact > allow_write > allow_read > default
Deny always wins. This is unsurprising, matches firewall conventions, and prevents accidental widening.
| Variable | Resolves to |
|---|---|
${PROJECT} |
The directory aixgate run was invoked from. |
${HOME} |
The current user's home directory. |
${TMPDIR} |
The current user's temp directory. |
${AIXGATE_CONFIG_DIR} |
~/.aixgate. |
Aixgate uses doublestar semantics:
*matches any non-slash characters.**matches any number of path segments including zero.?matches a single character.[abc]matches a character class.{foo,bar}matches alternatives.
# JSON Schema equivalent in YAML form
profile: string # Required. Profile name.
extends: string # Optional. Another profile to extend.
default: "deny" | "allow" # Default action. v1 recommends deny.
filesystem:
allow_read: [glob] # Paths agent may read.
allow_write: [glob] # Paths agent may write.
redact: [glob] # Paths returned as redacted stubs.
deny: [glob] # Paths always denied (highest precedence).
exec:
allow: [string] # Allowed command basenames.
deny: [string] # Denied command basenames.
deny_args:
<command>: [string] # Denied argument patterns per command.
env:
pass_through: [string] # Env vars passed through.
inject:
<key>: <value> # Env vars injected.
strip: [string] # Env vars explicitly stripped.
audit:
log: path # Audit log file path.
on_deny: "log" | "prompt" | "block_silently"
on_allow: "log" | "none" # Default: logOne JSON object per line (JSONL), structured to be trivially queryable with jq, grep, or ingested into a SIEM.
{"ts":"2026-04-20T10:12:33Z","profile":"claude-code","pid":4421,"session_id":"01HV2K...","op":"read","path":"/Users/cg/code/project/.env","decision":"redact","rule":"redact:**/.env","agent_cmd":"claude"}| Field | Description |
|---|---|
ts |
ISO 8601 timestamp, UTC. |
profile |
Active profile name. |
pid |
PID of the process requesting access. |
session_id |
Unique identifier for this aixgate run invocation (ULID). |
op |
Operation: read, write, stat, exec, unlink, rename. |
path |
Canonicalized absolute path. |
decision |
allow, deny, redact, or prompt. |
rule |
Identifier of the rule that produced the decision. |
agent_cmd |
Top-level command that was launched by aixgate run. |
Audit logs rotate at 100MB by default, keeping 10 files. Configurable via ~/.aixgate/config.yaml. Aixgate does not delete logs automatically beyond rotation; retention is the user's decision.
# Everything denied in the last day
aixgate audit query --since 24h --denied-only
# Every time .env was touched
aixgate audit query --path '**/.env*'
# Every exec call for a specific session
aixgate audit query --session-id 01HV2K... --op exec
# Live tail filtered to one profile
aixgate audit tail --follow --profile claude-code- Signed macOS universal binary (arm64 + x86_64), distributed as a plain
.tar.gz. No.pkgneeded — no kernel extension to install. - Linux static binary for x86_64 and arm64, distributed as
.tar.gzand.deb. - Homebrew tap:
brew install aixgo-dev/tap/aixgate. - Shell installer:
curl -sSL https://aixgo.dev/aixgate/install.sh | sh.
| Dependency | Purpose |
|---|---|
| Pure Go, no cgo | Aixgate is pure Go. No C toolchain required to build. No cgo symbols in the binary. |
sandbox-exec (macOS) |
Host-provided binary invoked via exec.Command. Ships with every macOS version; no install needed. |
| FUSE (Linux) | Kernel module available by default on most distributions; userland support via fuse3 package. Loaded lazily on first aixgate run. |
| No external runtime | Aixgate does not require Docker, VMs, macFUSE, or a background daemon. |
MIT, matching aixgo.dev. Contributions accepted under a lightweight DCO (Developer Certificate of Origin).
Aixgate is the security and runtime isolation primitive in the aixgo.dev ecosystem. The cross-project story is documented in detail in the Aixgo PRD § 12; this section covers the same relationship from Aixgate's side.
The relationship is intentionally layered:
| aixgo.dev project | Role |
|---|---|
| aixgo (framework) | Build agents: orchestration patterns, LLM providers, memory, tools. See https://github.com/aixgo-dev/aixgo. |
| Aixgate | Run agents safely on developer workstations. Enforces filesystem and exec policy at the OS boundary. |
| aixgo-cloud (future) | Run agents safely in server and CI environments. Shares policy format with Aixgate. |
This layering gives aixgo.dev a credible answer to the single most common security question asked about agent frameworks: "how do I stop it from reading my credentials?" Aixgate's existence strengthens the framework's positioning for enterprise and security-conscious adopters, and in turn the framework's community distribution accelerates Aixgate's adoption.
- aixgo agents can detect the
AIXGATE_ACTIVE=1environment variable and surface sandboxed status in their UI, giving users confidence that their boundaries are being enforced. - aixgo's built-in tool definitions (
file_read,shell_exec) can optionally emit additional context into Aixgate's audit log via a local socket, enabling per-tool-call attribution rather than per-syscall. - Shared policy schema: the same
.aixgate.yamlfile will eventually be interpretable by aixgo-cloud's server-side enforcement, enabling "write policy once, enforce everywhere."
- Aixgate is not bundled with aixgo. An agent built on aixgo may run without Aixgate, and Aixgate sandboxes agents built on anything.
- The aixgo framework does not depend on Aixgate. The dependency is one-way and optional.
- Marketing message: "aixgo.dev builds agents. Aixgate keeps them in their lane."
- FUSE overlay on macOS and Linux that hides
.env,~/.ssh/id_*,~/.aws/credentialsby default. aixgate runcommand with hardcoded policy.- No configuration, no audit log, no profiles. Single purpose: prove the enforcement boundary holds across at least three agents (Claude Code, Aider, a custom Go agent from aixgo).
- YAML policy file support.
- Built-in profiles for Claude Code, Aider, and a generic default.
- Structured audit log with
tailandquerycommands. aixgate doctordiagnostic command.- Published to Homebrew and Linux packages.
- Prompt-on-access with desktop notifications.
- Project-local
.aixgate.yamldiscovery andextends:-style composition. - Signed installers, notarization, first-run UX polish.
- Documentation site, example policies, and integration guides for the top five agents.
- Launch blog post and BSides Tokyo talk.
- Windows support via a WFP-based filesystem filter.
- Optional network egress policy via a local HTTPS proxy.
- Rego policy backend for organizations with existing OPA investment.
- Server-side variant for CI and Kubernetes: aixgo-cloud integration.
- eBPF-based enforcement on Linux as an optional belt-and-braces layer.
- Policy marketplace: community-contributed profiles for specific frameworks, languages, and cloud providers.
- GitHub stars on the
aixgaterepo: 500 within 3 months of v1.0 launch; 2,500 within 12 months. - Homebrew install count: 1,000 weekly active installs within 6 months of v1.0.
- At least 5 community-contributed profiles for agents not authored by the core team.
- Zero known policy-bypass vulnerabilities in v1.0. A responsible disclosure policy is in place.
- False positive rate (legitimate agent operations incorrectly denied): under 5% on the default Claude Code profile, measured against a benchmark of 50 common coding tasks.
- p95 read latency overhead versus native filesystem access: under 10ms on an NVMe SSD.
- Startup overhead of
aixgate runversus direct launch: under 500ms.
- Aixgate is cited in at least one public post-mortem where it prevented credential exposure.
- Aixgate drives measurable traffic and conversion to aixgo.dev the framework, as tracked by referrer analytics on docs and GitHub.
- At least one enterprise adopter references Aixgate in a security questionnaire response.
| Risk | Impact | Mitigation |
|---|---|---|
macOS sandbox-exec is Apple-deprecated (has been for years); future macOS could remove it. |
High | Binary still ships in every macOS release through 2026 and is used by Apple's own tooling. Document a FUSE-T + hanwen/go-fuse fallback path; build the Sandbox interface so the implementation can swap without touching callers. aixgate doctor detects and warns if sandbox-exec is missing. |
| Agents fork subprocesses that escape the sandbox. | High | Rely on mount namespaces (Linux) and sandbox-exec child inheritance (macOS) rather than FUSE-only enforcement. Add landlock where available. |
| Symlink and path traversal bugs in the overlay leak data. | High | Canonicalize before every policy check. Comprehensive test suite including adversarial traversal cases. Third-party security review before v1.0. |
| Policy complexity leads to footgun allowlists. | Medium | aixgate policy check warns on overly broad rules. Ship safe defaults. Document common patterns. |
| FUSE performance overhead breaks agent UX. | Medium | Benchmark against native. Cache policy decisions per path per session. Optimize hot paths. |
| Risk | Impact | Mitigation |
|---|---|---|
| Users assume agent vendors' built-in sandboxes are sufficient and Aixgate is redundant. | Low | The premise is empirically false on two fronts. First, vendor sandboxes get bypassed routinely. Cursor's YOLO mode accumulated seven CVEs in 2025 including shell-builtin and obfuscation bypasses of the denylist; a Claude Code agent at Ona discovered /proc/self/root/usr/bin/npx to bypass the denylist, and when bubblewrap blocked that path the agent simply disabled the sandbox itself; Google Antigravity's "secure mode" was defeated by prompt-injection-to-RCE; CVE-2025-54795 (Claude Code) and GHSA-534m-3w6r-8pqr (Cursor) are argument-injection bypasses of pre-approved commands. Agents are designed to break out when they decide a goal needs it; vendors are still patching new bypasses every quarter. Second, vendor-only sandboxing requires trusting the same vendor with both execution and audit. An audit trail written by the audited process is not an audit trail — when the agent is compromised, its log becomes part of the attack surface. Aixgate enforces at the OS boundary (Landlock + seccomp on Linux, sandbox-exec on macOS) below the agent's reach, and writes its audit log from the host process, not the agent. Defense-in-depth and vendor-independence, not redundancy. |
| Users disable Aixgate because the default profile is too strict. | High | Ship permissive-but-safe defaults. Make it easy to allow specific paths on the fly. Prioritize the "it just works" path for popular agents. |
| Open source positioning conflicts with future commercial offering. | Medium | Commit clearly that the core enforcement and policy engine are MIT forever. Commercial layer, if any, is around managed policy distribution, SIEM integration, or enterprise support — not gating core features. |
- Should we support a "learning mode" that observes agent behavior and suggests policy? Useful for first-time users but potentially a security anti-pattern.
- How do we handle agents that legitimately need a one-off read of a sensitive file (for example, reading a
.envto verify a variable is present)? Redaction? Prompt? Neither? Should the audit log be tamper-evident (hash chain, append-only) by default, or is that over-engineering for v1?Resolved (May 2026): tamper-evident audit logging is foundational, not over-engineering. The whole point of a host-written log is that an independent reviewer (operator, engineer, auditor) can verify what the agent did without trusting the agent or the host. Hash-chained append-only by default; cryptographic signing for the v0.2 SIEM integration path. See §13.2 for context.- Is there a meaningful difference between "Aixgate" as a standalone product and
aixgo aixgateas a subcommand of an eventualaixgoCLI? Naming decision to revisit before launch. - Should
.aixgate.yamlsupport environment-specific overrides (dev vs staging vs demo contexts)?
This section is intended to be read by Claude Code and human contributors working in the aixgo.dev repo.
| Concern | Library | Notes |
|---|---|---|
| CLI | spf13/cobra |
Consistent with aixgo's existing CLI patterns. |
| Config | spf13/viper + goccy/go-yaml |
YAML parsing with line-number errors. |
| FUSE (Linux) | hanwen/go-fuse |
Pure-Go FUSE library, no cgo. Actively maintained; nodefs/pathfs layers. |
| Landlock (Linux) | landlock-lsm/go-landlock |
Pure-Go Landlock bindings. Linux 5.13+, ABI v4+ for network. Defense-in-depth. |
| Seccomp (Linux) | elastic/go-seccomp-bpf |
Pure-Go seccomp-bpf filter. Blocks ptrace, mount, bpf. NOT seccomp/libseccomp-golang (cgo). |
| Sandbox (macOS) | sandbox-exec via os/exec (stdlib) |
Host-provided binary. Generate SBPL profile, invoke with exec.Command. |
| Globs | bmatcuk/doublestar |
Supports ** and brace expansion. |
| Logging | log/slog (stdlib) |
Structured logs by default. |
| Audit | log/slog JSONHandler + natefinch/lumberjack for rotation |
|
| ULIDs | oklog/ulid |
Session IDs. |
| Testing | stdlib testing + stretchr/testify |
Match aixgo conventions. |
- The policy engine is pure. Given a policy and an access request, it returns a decision. It does not perform I/O, log, or have side effects. This makes it trivially testable.
- The FUSE overlay only implements the minimum filesystem operations needed. Prefer refusing exotic operations (
ioctl, xattr) to implementing them partially. - Path canonicalization happens exactly once per request, at the top of the policy check. Never trust a path that has not been canonicalized.
- Audit log writes are fire-and-forget from the FUSE hot path. Use a buffered channel; block on it only if the buffer is full, and prefer to drop with a counter metric rather than stall the agent.
- Platform-specific code lives in files suffixed
_darwin.go/_linux.go. Shared logic lives in the unsuffixed file. Use Go build tags only where necessary. - No cgo anywhere. All dependencies must be pure Go. On Linux, FUSE goes through
hanwen/go-fuse; on macOS, sandboxing goes throughsandbox-execinvoked viaos/exec. This keeps binaries small, cross-compilation trivial, and eliminates the C-toolchain requirement for contributors. - Platform mechanisms are asymmetric. Linux uses FUSE as the primary enforcement (per-op policy eval + rich audit); macOS uses
sandbox-execas the primary (kernel-enforced SBPL policy + OS log audit). Both sit behind aSandboxinterface so the rest of the codebase is platform-agnostic.
- Unit tests for the policy engine (
internal/policy). Exhaustive table-driven tests covering precedence, variable substitution, glob semantics, and malformed input. - Integration tests for the FUSE overlay using a temporary mount and a known policy. Assert that specific reads return
ENOENT, specific writes fail, and allowed paths pass through. - Adversarial tests for path canonicalization: symlink loops,
..traversal, null bytes, unicode normalization edge cases. - End-to-end tests in
test/e2ethat launch real agents (or scripted agent mocks) inside Aixgate and verify behavior. These are slow and live outside the defaultgo test ./.... - Benchmarks for policy decision latency and FUSE throughput.
- Follow
gofmt,goimports, andgolangci-lintwith the aixgo.dev shared config. - Errors wrap with
fmt.Errorf("context: %w", err); never bare-return. - No
init()functions except for registering cobra commands and embedded profiles. - Every exported function in
pkg/aixgatehas a godoc comment starting with the function name. - Internal packages (
internal/...) are not stable API; do not depend on them from outside the repo.
Before v1.0:
- Third-party security review of the FUSE overlay and path canonicalization.
- Fuzz testing of the policy parser and glob matcher.
- Threat model review against the documented boundary in §6.6.
- Responsible disclosure policy (
SECURITY.md) and a signed PGP key for vulnerability reports.
README.md— installation, quickstart, link to docs site.docs/— full user documentation, policy cookbook, profile authoring guide.CLAUDE.md— instructions for Claude Code contributors (architecture overview, dev loop, testing commands, PR conventions).SECURITY.md— threat model, reporting process.CONTRIBUTING.md— DCO, code style, PR process.- Per-profile docs in
docs/profiles/explaining the rationale for each rule in each default profile.
Status (May 2026): v0.1.0 has shipped. See https://github.com/aixgo-dev/aixgate/releases/latest. This section is preserved as a historical record of the original scope and as guidance for contributors approaching the codebase. The roadmap for what comes next lives in § 11.
A concrete, scoped proof-of-concept that a contributor (human or Claude Code) can complete in a weekend. The goal was to validate the enforcement boundary and the UX hypothesis, not to ship a product.
- Single Go binary named
aixgate, built pure Go (no cgo). - One command:
aixgate run -- CMD [ARGS...]. - Hardcoded policy: hide every file matching
**/.env,**/.env.*,~/.ssh/id_*,~/.aws/credentialsby returningENOENT(Linux, via FUSE) or denyingfile-read*in the generated SBPL profile (macOS, viasandbox-exec). Everything else passes through. - macOS + Linux support. One platform is enough for the PoC; the other may be stubbed behind the
Sandboxinterface. - No config, no audit log, no profiles, no tests beyond a minimal smoke check.
- Stand up the
Sandboxinterface and a pass-through implementation for the contributor's platform.- On Linux: mount a pass-through FUSE overlay via
hanwen/go-fuse.aixgate run -- ls ~works and shows the real home directory through the FUSE mount. - On macOS: generate an SBPL profile that allows everything, write it to a temp file, and exec the agent via
sandbox-exec -f profile.sb -- CMD.aixgate run -- ls ~works and shows the real home directory under the sandbox.
- On Linux: mount a pass-through FUSE overlay via
- Add the deny rules.
aixgate run -- cat ~/.ssh/id_rsareturns "No such file or directory" on Linux (FUSEENOENT) and an access-denied on macOS (sandbox deny).aixgate run -- cat ~/.aws/credentialssame.aixgate run -- ls ~/.sshdoes not showid_*files on Linux; on macOS the files are visible inlsbut unreadable (SBPL can't hide existence, only deny access — document this platform asymmetry). - Verify against a real agent. Launch Claude Code inside
aixgate runin a directory containing a.env. Confirm the agent reports it cannot find or read the file, and does not surface the contents in any form. - Verify subprocess containment.
aixgate run -- bash -c "cat .env"also fails, proving that forked children inherit the sandbox on both platforms (mount namespace on Linux; SBPL is per-process-tree on macOS).
-
go build ./cmd/aixgateproduces a working binary on the contributor's platform. - The four hardcoded paths are provably hidden from shell commands launched via
aixgate run. - At least one real AI agent (Claude Code preferred) has been tested inside the sandbox and its logs/UI confirm it cannot see the protected paths.
- A 200–400 word writeup of what worked, what didn't, and what the UX surprises were. This becomes the basis for the launch blog post and informs v0.2.
Everything else in this PRD. Resist the urge to build the policy engine, audit log, profiles, aixgate doctor, installers, or documentation beyond a two-paragraph README. The goal is to learn, not to ship.
| Term | Meaning |
|---|---|
| Agent | A process driven by an LLM that reads and writes files, runs commands, and otherwise acts on the user's behalf. |
| FUSE | Filesystem in Userspace. Lets a userspace program provide a filesystem that the kernel exposes to other processes. |
| Landlock | A Linux kernel feature (5.13+) that lets a process voluntarily drop filesystem access, used as defense in depth. |
sandbox-exec |
A macOS tool that launches a process under a TrustedBSD sandbox profile. Used extensively by Apple's own system components. |
| Profile | A named set of Aixgate policy defaults, typically shipped with the binary and specialized per agent. |
| Policy | The effective rule set governing a Aixgate session, composed from profile defaults and project-local overrides. |
| Canonicalization | The process of resolving a path to its absolute, symlink-free, ..-free form before policy evaluation. |
| ULID | Universally unique, lexicographically sortable identifier. Used for session IDs. |
- Aqua Security, Falco, and Tetragon for container runtime protection. These informed the "enforcement at the OS boundary, not the application" thesis.
- Bubblewrap and Flatpak on Linux for user-space process isolation primitives.
- Apple's
sandbox-execand App Sandbox for the macOS enforcement model. - Deno's permission model as an example of what built-in, policy-based runtime security looks like when done well.
- Docker's
--read-onlyandtmpfsmount patterns for the "present a filtered filesystem view" primitive. - OpenBSD's
pledge(2)andunveil(2)for the general design principle of restricting a process to the minimum it needs.
- Linux FUSE documentation
- hanwen/go-fuse — pure-Go FUSE library
- Landlock LSM and landlock-lsm/go-landlock
- elastic/go-seccomp-bpf — pure-Go seccomp-bpf
- OWASP LLM Top 10 — Prompt Injection
- Apple sandbox profile language reference (unofficial)
- ADR 0001: Aixgate lives in the aixgo monorepo
| Version | Date | Author | Notes |
|---|---|---|---|
| 0.1 | April 2026 | Charles Green | Initial draft. |
| 0.2 | April 2026 | Charles Green | Rebrand Warden → Aixgate. |
| 0.3 | April 2026 | Charles Green | Replace cgofuse with pure-Go sandbox stack (hanwen/go-fuse + go-landlock + go-seccomp-bpf on Linux, sandbox-exec on macOS). Confirm aixgate lives in the aixgo monorepo — see ADR 0001. |
| 0.4 | May 2026 | Charles Green | Rename jail/Jailer to sandbox/Sandbox throughout (legacy terms left over from the Warden→Aixgate rebrand). Document v0.1 weekend-build PoC results in PR #3. |
End of document.