Why Agent Plugins Are Not a Security Boundary: From Advisory Hooks to a Kernel-Enforced Agent Runtime
When an autonomous agent shares a privilege domain with its supervisor, hooks and system prompts are merely polite suggestions. This monograph details how Aegis OS lowers the enforcement boundary into the OS kernel via parent-process sandboxing, read-only .git pass-through, granular state-dir mounts, and a two-tier network gateway.
01. Honest Threat Modeling: Why Agent Plugins & Hooks Are Advisory, Not Enforced
The most dangerous architectural illusion in AI agent infrastructure is mistaking a workflow orchestration plugin for an operating system security boundary. Modern terminal and IDE agents—including Claude Code, OpenCode, Codex CLI, Antigravity (AGY), and Hermes—typically expose three extension surfaces: system prompt instructions (CLAUDE.md / AGENTS.md), tool interception hooks (PreToolUse hooks and plugins), and Model Context Protocol (MCP) servers.
Under benign collaboration, plugin-based governance works remarkably well: hooks can transparently intercept native Read, Edit, and Bash calls and reroute them into an Aegis OS Copy-on-Write (CoW) shadow workspace. Yet the moment we inspect the process tree from the OS kernel’s perspective, an inescapable truth emerges: in plugin mode, the agent main process itself runs directly inside the host user’s privilege domain, inheriting the human developer’s exact UID, $HOME visibility, and raw system call surface.
No interceptor that executes within the same privilege domain as the supervised process—or relies on the supervised process to voluntarily invoke it—can ever be a security boundary. Unless the agent process tree itself is confined inside an OS kernel sandbox (Linux Mount/PID/Network namespaces + Landlock/seccomp, macOS Seatbelt, or a microVM), hooks and MCP provide Advisory Governance, not Enforced Isolation.
During our end-to-end security audit across mainstream CLI and desktop agents, we cataloged six structural bypass vectors that plugin-only governance cannot eliminate:
| Bypass Vector | Mechanism & Real-World Client Behavior | Why Hooks / Plugins Alone Cannot Fix It |
|---|---|---|
| 1. Uncovered Native & 3rd-Party Tools | Built-in tools like NotebookEdit, LSP refactoring actions, or project-injected .mcp.json servers (e.g., a raw filesystem MCP) |
Hooks rely on denylisting known tool names; any newly added client tool or unknown MCP server mutates the host directly |
| 2. Clients Without Tool-Level Hooks | Clients such as Codex CLI support MCP servers and native sandboxing but do not currently expose an external PreToolUse interception hook |
Routing relies entirely on soft prompt instructions in AGENTS.md, offering zero hard resistance against prompt injection |
| 3. Shared Daemon Escape | When OpenCode TUI connects via --attach to an already-running background server, plugin enforcement depends on the daemon’s startup state |
A CLI wrapper cannot retroactively sandbox or inject plugins into a pre-existing host daemon process |
| 4. Self-Modifying Config & Local Overrides | An agent or build script modifies ~/.claude/settings.json, .claude/settings.local.json, or ~/.config/opencode/opencode.json |
Because the agent has write access to its own config directory, it can strip its own hooks for subsequent turns or sessions |
| 5. Host Side-Effects in "Read-Only" Commands | Allowing seemingly benign commands like git status, cargo test, or npm test to run on the host workspace |
build.rs, postinstall scripts, or core.fsmonitor in .git/config execute arbitrary host code and can read ~/.ssh |
| 6. Loopback Self-Approval | A local subprocess sends an HTTP request to the local broker on 127.0.0.1 to approve its own pending escalation ticket |
Without cryptographic separation between Agent Session Tokens and Human Admin Tokens, a same-UID process can forge approvals |
02. Three-Tier Enforcement (Advisory / Enforced / Isolated): Decoupling Ergonomics from Security
Acknowledging the limits of plugins does not mean abandoning them. In systems engineering, the two worst mistakes are breaking 95% of daily developer workflows with overly brittle defaults, or overclaiming security guarantees that do not hold under adversarial conditions. Aegis OS therefore defines three explicit, verifiable Enforcement Tiers, reported transparently in real time via aegis-os status and aegis-os doctor:
03. Inverting Control: The aegis-os run Parent Launcher, Read-Only .git View & State-Dir Layering
Moving from Advisory to Enforced requires a single foundational shift: inverting the parent-child process relationship. Instead of an agent living on the host and optionally calling Aegis, aegis-os run -- <agent> acts as the parent process—constructing a restricted kernel namespace first and spawning the agent binary inside it.
Yet placing a full-featured modern CLI agent (such as Claude Code or OpenCode) inside a Linux bubblewrap (bwrap) + Landlock + seccomp or macOS Seatbelt sandbox immediately surfaces three practical systems challenges: (1) distro-specific dynamic linkers and package stores (NixOS, Linuxbrew, Snap) failing with ENOENT; (2) git status and git diff breaking or triggering malicious host Git hooks; and (3) the agent either losing its session history (~/.claude/projects) or retaining the ability to overwrite its own security settings (~/.claude/settings.json).
Aegis Enforced Runtime resolves all three without sacrificing security or developer ergonomics:
3.1 Distro-Compatible Root Masking (--ro-bind / /) & Path Remapping
Manually enumerating /usr and /lib breaks immediately on NixOS (/nix/store), Linuxbrew (/home/linuxbrew/.linuxbrew), and custom enterprise CA bundles. On Linux, Aegis preserves --ro-bind / / for universal binary compatibility, then immediately masks user and runtime state by mounting fresh --tmpfs over /home, /root, /run, /var, /tmp, /mnt, /media, and sensitive /etc credential files. Finally, it bind-mounts the writable CoW shadow workspace directly onto the original host project path (/home/user/project) while mounting the real host tree read-only at /aegis/host/project. Even if a prompt-injected agent bypasses every MCP tool and runs python -c "open('src/lib.rs', 'w')", the kernel transparently redirects the write into the isolated CoW shadow.
3.2 Read-Only .git Object Pass-Through with GIT_INDEX_FILE Separation
Both developers and agents rely heavily on git status, git diff, git log, and prompt branch indicators. Stripping .git from the shadow breaks Git tooling; copying .git wastes hundreds of megabytes on large repositories; and exposing the host .git writable allows an agent to achieve host code execution by writing to .git/hooks/pre-commit or setting core.fsmonitor in .git/config.
Aegis OS solves this via a Read-Only Object Store + Per-Session Writable Index + Hardened Git Shim:
# 1. Bind-mount the host .git directory read-only into the shadow workspace
bwrap ... --ro-bind /aegis/host/project/.git /home/jz/project/.git
# 2. Copy only the single-file .git/index into the private session dir and redirect Git's index pointer
cp /aegis/host/project/.git/index ~/.aegis/sessions/$SESSION_ID/git-index
export GIT_INDEX_FILE="$HOME/.aegis-git-index"
export GIT_OPTIONAL_LOCKS=0
export GIT_CONFIG_NOSYSTEM=1
export GIT_CONFIG_GLOBAL=/dev/null
# 3. Prepend a Git safety shim that disables external diff/fsmonitor helpers and routes mutations to aos commit
git -c core.fsmonitor=false -c core.hooksPath=/dev/null status --no-ext-diff
This guarantees zero-copy .git/objects access and instant git status / git diff across 100k-file repositories while ensuring the host’s .git/index mtime is never touched and repository hooks can neither be modified nor executed.
3.3 Granular Agent State-Directory Layering (Single-File Read-Only Config Locks)
CLI agents must write conversation logs, todo lists, and OAuth refresh tokens at runtime (e.g., ~/.claude/projects/*.jsonl, ~/.codex/sessions, or OpenCode’s SQLite state in ~/.local/share/opencode), but they must never be allowed to modify ~/.claude/settings.json, ~/.gemini/config/hooks.json, or ~/.codex/config.toml. Leveraging ordered mount layering in bwrap, Aegis mounts state subdirectories writable first and then overlays single-file --ro-bind locks onto every security-critical configuration file—preserving full stateful session continuity while making self-modification of hooks and permissions kernel-impossible.
aegis-os run.04. Effect-Driven Policy & Dual-Mode Egress: Separating CONNECT Tunnels from L7 Reverse Proxies
A pervasive anti-pattern in agent security is prompting the user to approve raw shell command strings. Commands are not security primitives; Effects are. Running cargo test reads and writes hundreds of files inside the build directory, yet as long as those effects are confined to the disposable CoW shadow workspace and read-only toolchains, the user should never be interrupted. Conversely, a single file write that touches .github/workflows/release.yml or build.rs represents a high-risk persistence vector when committed back to the host.
Aegis OS models every operation as a structured (EffectKind, ResourceScope, Reversibility) tuple evaluated by our Cedar policy engine. Reversible mutations inside the shadow workspace are auto-allowed with automatic snapshots; irreversible boundary transitions (workspace.commit, workspace.commit_sensitive, out-of-workspace reads, or unallowlisted network egress) require a capability lease or human approval.
For network egress inside --unshare-net, we also reject the dishonest industry claim that a standard HTTPS CONNECT proxy provides L7 Data Loss Prevention (DLP). Because CONNECT establishes an end-to-end encrypted TLS tunnel, the proxy only observes host:port and byte counts—never the HTTP method, path, or request body. Aegis OS therefore separates egress into explicit modes:
- Mode 1: L4
CONNECTTunnel (Default for package managers & general HTTPS) — Evaluatesnet.connectagainst domain/port allowlists with zero streaming latency and zero TLS certificate breakage, without fabricating L7 method logs. - Mode 2: L7
Base URLReverse Proxy (Default for LLM & SaaS APIs) — The launcher pointsANTHROPIC_BASE_URL/OPENAI_BASE_URLto a local gateway. The gateway inspects full L7net.requestmethods and paths, scans request bodies for PHI/secrets before forwarding, injects API keys at the boundary so raw credentials never enter the sandbox environment, and streams SSE responses without buffering time-to-first-token. - Mode 3: Opt-in MITM (Explicit enterprise domains only) — Issues a per-session CA strictly for domains listed in
mitm_domains, failing closed or visibly downgrading if a binary uses hardcoded certificate pinning.
05. Generalized Domain Commit Pipelines & Non-Destructive TUI Approvals
Autonomous agents are no longer confined to software repositories; they author research manuscripts (Documents), clean clinical cohorts (Data), generate figures (Binary), and mutate live enterprise software (AppState). A runtime that only understands git diff leaves non-code workflows completely unprotected.
Aegis Enforced Runtime generalizes the shadow → verify → approve → land transaction pipeline across domains via declarative DomainProfile configurations:
- Code & Documents: 4-tier LCS 3-way auto-merge with sandboxed pre-flight verification gates (
cargo test,latexmk -pdf, citation & link checks), pairing in Phase 5 with Heurion’s Dual-Surface CRDT block locks andpatchParagraphbyte-preserving OOXML splicer for Word/PowerPoint archives. - Binary Assets (Figures, PDFs, Medical Imaging): Because binary files cannot be merged line-by-line, Aegis enforces exclusive
coord_claimlocks and records a baseline SHA-256 hash at shadow creation—requiring explicitoverwrite_binariesapproval with before/after hash evidence prior to landing on the host. - Data & Content-Addressed Pipelines (Org CAS): Upstream data agents must pass schema validation and
scanPhi --strictinside the sandbox before publishing immutable SHA-256 artifacts viaorg_artifact_publish, structurally preventing downstream agents from reading half-written files.
When Claude Code, OpenCode, or Codex is rendering a full-screen Alternate Screen TUI in raw mode, having a parent supervisor write approval text directly to the shared PTY’s stderr—or compete for stdin keystrokes—instantly corrupts the terminal layout and deadlocks input. When a full-screen TUI is active, Aegis OS never writes raw approval text into the main screen: instead, it notifies the human out-of-band via desktop notifications, terminal OSC 0 title bar badges (⏳ Aegis: 1 approval pending), a companion aegis-os approve CLI in a second terminal, or the SHA-256 diff-locked local Web console (with an optional 1-line DECSTBM scroll-region status bar for headless SSH). Only when kernel security respects terminal physics will developers keep enforcement enabled by default.
Reader Comments
0 commentsNo comments yet. Share your thoughts or technical questions below.