Blog
Published on

Containing AI Agents: Filesystem, Secrets, and Egress Boundaries

Authors
  • avatar
    Name
    Jared Chung
    Twitter

Introduction

An agent that can edit code, run commands, and call APIs is useful because it can affect real systems. Those same capabilities create its blast radius: the maximum damage possible when the user, model, tool output, or surrounding software makes a mistake.

Permission prompts help, but frequent prompts train people to approve them quickly. Model-based classifiers help, but probabilistic controls can miss unusual actions. The strongest boundary is deterministic: do not give the execution environment access it does not need.

The examples use synthetic files, credentials, and services to demonstrate containment principles without claiming complete isolation.

Containment explorer

THREAT MODEL / CAPABILITY BOUNDARIESWORKSPACECREDENTIALSNETWORKAIAGENTFILESKEYWEBa permission is a hole in the boundary

Open gates

Choose capability grants and run a synthetic action.
See capability grants expand the blast radius. Grant only what a task needs, then test a harmless synthetic action against the resulting boundary.

Start With a Capability Inventory

Before choosing a container or virtual machine, describe the work in terms of capabilities.

CapabilityExample requirementSafer boundary
Filesystem readInspect one repositoryRead-only mount of that path
Filesystem writeModify source filesWritable workspace, no home directory
Process executionRun testsRestricted user and resource limits
NetworkFetch package metadataExplicit destinations and methods
CredentialsCreate a draft issueNarrow broker for one operation
PersistenceSave final artifactsDedicated output directory

The inventory should include deletion. “Read-write” often implies that files can be removed, so a no-delete mode may be a meaningful separate capability.

Match the boundary to the user's ability to review actions. A developer who understands a shell command can evaluate different prompts from someone using an agent through a document interface. Both still benefit from containment.

Make Filesystem Boundaries Real

Checking whether a requested path starts with an approved string is unsafe. Relative paths and symbolic links can point somewhere else. Resolve the real path before deciding whether it sits inside the allowed root.

from pathlib import Path


def require_inside(requested: Path, allowed_root: Path) -> Path:
    root = allowed_root.resolve(strict=True)
    target = requested.resolve(strict=False)

    if not target.is_relative_to(root):
        raise PermissionError(f"Path escapes workspace: {target}")

    return target

This application check is useful, but enforcement should also exist below the agent process. Mount only the required directories. Use read-only mounts for references and a dedicated writable directory for changes. Run the agent as an unprivileged user and limit processes, memory, and execution time.

Test the normal case and the escape attempts:

def test_symlink_cannot_escape(tmp_path):
    workspace = tmp_path / "workspace"
    workspace.mkdir()
    outside = tmp_path / "private.txt"
    outside.write_text("synthetic secret")
    (workspace / "shortcut").symlink_to(outside)

    try:
        require_inside(workspace / "shortcut", workspace)
        assert False, "escape should be denied"
    except PermissionError:
        pass

A test is not a proof that the container runtime has no vulnerabilities. It verifies that the policy you intended is actually applied to representative paths.

Keep Credentials Outside the Workspace

If a general API key is present in the environment, a process that can read its environment can use every permission attached to that key. Prefer short-lived, scoped credentials or a broker that performs one narrow action after checking policy.

def create_draft_issue(request, actor):
    if request.repository not in actor.allowed_repositories:
        raise PermissionError("repository is outside approved scope")
    if request.mode != "draft":
        raise PermissionError("only draft issues are allowed")

    return issue_service.create_draft(
        repository=request.repository,
        title=request.title,
        body=request.body,
        identity=actor.service_identity,
    )

The agent receives a tool for creating a draft issue, not a token that can call the entire provider API. Record the user, approved scope, payload hash, and resulting external identifier outside the agent-writable workspace.

Treat Egress as a Capability Grant

A hostname allowlist answers only “where can traffic go?” It does not answer “what can it do?” One allowed domain can expose file uploads, messaging, administration, and multiple accounts.

Anthropic described a case in which traffic to an allowed API domain carried files using an attacker-controlled key. The destination check worked as designed, but the allowed destination exposed a broader capability than intended.

A stronger proxy can bind destination, action, and identity:

def allow_request(destination, method, path, credential_owner):
    return (
        destination == "issues.example.test"
        and method == "POST"
        and path == "/drafts"
        and credential_owner == "workspace-service"
    )

Use a mock service when testing this pattern. Verify that an approved draft succeeds, an upload path fails, and an attacker-supplied credential is rejected.

Preserve Observability Outside the Boundary

Isolation can reduce visibility. A sealed environment may prevent host security tools from inspecting its processes. Plan audit access alongside isolation rather than discovering later that the sandbox is opaque.

Keep policy decisions and execution events outside the agent's writable boundary. Useful events include:

  • workspace mounts and modes;
  • denied filesystem paths;
  • destination, method, and policy decision for network requests;
  • credential-broker operations;
  • process start, termination, and resource-limit events.

Logs are evidence, not prevention. A successful-looking API call may already represent exfiltration. Enforce limits first, then use logs for investigation and improvement.

Conclusion

Agent security begins by deciding what the agent can reach. Give it the smallest useful filesystem, network, process, and credential capabilities, then test both legitimate work and escape attempts.

Human review and model-level safeguards still matter. They work best inside deterministic boundaries that cap the outcome when judgment fails.

References