Skip to content
Agentic Control Plane

Stop your AI agent from touching files outside your project — in three steps

David Crowe · 5 min read
governance defense-in-depth workspace-isolation filesystem-safety

A developer posted on the Cursor forum that the Cursor agent’s working directory escaped its repository, walked into ~/Documents, and recursively deleted the contents. A separate GitHub community discussion documented Copilot’s agent autocompleting a destructive command that wiped a user’s D: drive — ten years of personal photos and videos, gone. The agent didn’t choose either drive maliciously. It chose them because the command-construction prompt landed there.

Modern AI agents have access to your entire filesystem. The “project” you’ve opened in Cursor is a notional boundary — to the agent, it’s just one directory in a tree it can navigate freely. If your agent can cd ~/, it can rm -rf ~/. If your agent can cat /etc/passwd, it can rm /etc/passwd. The IDE’s project sidebar is a UX concept; the OS doesn’t enforce it.

This is one of the most common documented incident classes in the AI-agent forums right now, and one of the easiest to gate.

What “agent escaped the repository” actually means

The agent didn’t break out. It walked through an unlocked door. A few common ways this happens:

  • The user asked the agent to “back up some files” — agent guessed ~/Documents was the target
  • The agent’s path-construction prompt produced an absolute path instead of a relative one (e.g., /Users/dev/... instead of ./...)
  • The agent ran cd to look at something, then forgot to cd back, then ran a destructive command from the new working directory
  • A shell variable expanded unexpectedly (the Claude Code rm -rf ~/ tilde-expansion bug is the canonical example)

In each case the model believed it was operating inside the project. The shell — which has no concept of “the project” — happily executed somewhere else.

Irreversible actions live one tool call away

The home-directory case is uniquely painful because it tends to contain things that don’t exist anywhere else: uncommitted experiments, downloaded artifacts, configurations, personal files, the only copy of something you didn’t think to back up. Most code is reproducible from source control. Most of ~/Documents is not.

The probability of an agent in your environment doing this in the next 60 days is not low. It happens enough that there are dedicated GitHub issue threads tracking variants by month.

Three steps that pin your agent inside the project

Step 1 — Install the hook

For Cursor, Claude Code, or Codex CLI:

curl -sf https://agenticcontrolplane.com/install.sh | bash

Every file operation the agent attempts — Read, Write, Edit, and Bash commands that touch files (rm, mv, cp, dd, find -delete) — goes through ACP’s hook before execution. The hook receives the resolved absolute path (after tilde expansion, after working-directory composition), so policy can match against where the agent actually wants to write, not where the agent thinks it’s writing.

Step 2 — Deny file operations outside the project root

ACP classifies file operations by path — Read.env, Write.src, Bash.rm, etc. For workspace-scoping, you set policy on the path of the resolved target:

{
  "mode": "enforce",
  "workspace": {
    "allowedRoots": [
      "${project.root}",
      "/tmp/${project.id}"
    ],
    "deniedPaths": [
      "$HOME/Documents",
      "$HOME/Desktop",
      "$HOME/.ssh",
      "$HOME/.aws",
      "$HOME/.config",
      "/Volumes",
      "/etc",
      "/usr"
    ]
  },
  "tools": {
    "Write.*": {
      "background":  { "permission": "deny", "if": "path NOT IN workspace.allowedRoots" },
      "interactive": { "permission": "ask",  "if": "path NOT IN workspace.allowedRoots" }
    },
    "Bash.rm": {
      "background":  { "permission": "deny", "if": "path NOT IN workspace.allowedRoots" }
    }
  }
}

The semantic: any file operation whose resolved path lands outside the project root (or an explicit allow-listed scratch directory like /tmp) is denied in background tier and asked-about in interactive tier. The agent can do anything inside the project; outside the project, it can’t.

This catches the tilde-expansion bug, the wandering-cd bug, the absolute-path mistake, and the wrong-drive completion all in one rule.

Step 3 — Bind end-user identity, per request

For server-side agents, the user’s IdP role can additionally restrict which projects the agent can even access:

from acp_governance import set_context

set_context(
    user_token=jwt,
    agent_name="repo-maintenance",
    agent_tier="background",
    workspace_id="acme-payments-service",  # which project this run is allowed in
)

If a different project’s agent run somehow gets scheduled with this user’s token, the workspace mismatch denies the call. It’s a belt-and-suspenders defense — the path policy already catches “outside the project,” but workspace_id adds “this is the WRONG project entirely.”

(Free fourth step) — Audit log

Every denied path is logged with the resolved absolute path, not the agent’s original command string. So when you see “agent attempted Write to /Users/dev/Documents/family-photos/2024.zip in the dashboard, you know exactly which boundary it tried to cross — useful for tightening rules, useful for understanding why the agent ended up there.

The total time investment

  • One curl command (Step 1): ~30 seconds
  • Workspace-root + denied-paths config in the dashboard (Step 2): ~3 minutes
  • Optional workspace_id for server-side agents (Step 3): ~30 seconds per handler

Three to four minutes from blank slate to “an autonomous agent in this environment cannot write or delete files outside the project root, regardless of what path the model decided to construct.”

If you’ve ever had a moment where you watched the agent type a path and thought “wait, that’s not where I think we are,” three minutes of work makes that thought retroactive instead of urgent.

AgenticControlPlane.com

Get the next post
Agentic governance, AgentGovBench updates, the occasional incident post-mortem. One email per post. No marketing fluff.
Share: Twitter LinkedIn
Related posts

← back to blog