Gitfence

Least-Privilege Repo Access for Claude Code, Codex, Cursor

How to give Claude Code, Codex and Cursor least-privilege repository access with permission rules, sandboxes, scoped tokens and filtered clones.

Gitfence team7 min read

Short answer: Least privilege for a coding agent means three things: it can only read the code its task needs, it can only change the paths it should, and it can't send data anywhere you didn't approve. Agent permission settings and sandboxes handle the last two on your own machine. Limiting what the agent can read is most reliable when the code isn't in its clone in the first place, because anything on disk is reachable from a shell.

This guide covers the controls built into Claude Code, Codex and Cursor, what each one enforces, and how to scope the repository itself.

The layers of agent access

Layer Question Typical control
Tool permissions Which actions can the agent take without asking? Allow/ask/deny rules, approval policies
Sandbox What can processes the agent starts read, write and reach on the network? OS sandbox, container, VM
Credentials What can the agent's tokens do on GitHub and elsewhere? Scoped, expiring tokens
Repository contents What code exists in the agent's working copy at all? Separate repos, filtered views

Most guides stop at the first two. The last two matter because agents often run on machines you don't control (a contractor's laptop, a cloud runner) and because prompt injection can make an agent use any capability it has.

Claude Code

Claude Code's permission rules live in .claude/settings.json (shared) or managed settings (enforced by your organization). Deny rules win over allow rules.

{
  "permissions": {
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./core/**)",
      "Edit(./.github/workflows/**)",
      "Bash(curl *)",
      "Bash(wget *)"
    ]
  }
}

What these enforce, per the docs:

  • Read and Edit deny rules apply to the built-in file tools, to commands Claude Code recognizes such as cat, head, tail, sed and tee, and to redirection targets.
  • They "don't apply to a command that reads files without naming them, such as grep -r pattern . ... or to arbitrary subprocesses that read or write files indirectly, like a Python or Node script that opens files itself."
  • Bash rules match command text, and a deny rule "isn't a security boundary around the program": the same program invoked another way can slip past.

For enforcement that doesn't depend on command text, Anthropic points to the sandbox, which restricts filesystem and network access for Bash commands and their child processes. Use both.

Codex

Codex uses an OS-level sandbox with three modes: read-only, workspace-write (the default) and danger-full-access, plus an approval policy. In workspace-write, the agent "can read files, edit within the workspace, and run routine local commands", and network access is controlled separately.

# ~/.codex/config.toml
sandbox_mode = "workspace-write"
approval_policy = "on-request"

[sandbox_workspace_write]
network_access = false

Key point: the sandbox limits writes and network. Within the workspace, the agent can read every file. If core/ is in the repository, it's readable.

Cursor

Cursor's .cursorignore excludes files from indexing, Tab, Inline Edit, Agent file access and @ mentions:

# .cursorignore
core/
.env*
infra/secrets/

Cursor's documentation is upfront: "The terminal and MCP server tools used by Agent cannot block access to code governed by .cursorignore," and "complete protection isn't guaranteed due to LLM unpredictability." Treat it as context hygiene, not a boundary.

Scope the credentials

Whatever the agent runs with, its credentials define the worst case:

  • Don't give agents your personal GitHub token. Use a fine-grained token or GitHub App limited to specific repositories, minimum permissions, and an expiry.
  • Agents that open PRs need write access to the repository on GitHub, which means read access to every path in it.
  • Keep deployment and cloud credentials out of the agent's environment unless the task needs them.

Scope the repository

All of the above leaves one gap: if the agent can read the repository, it can read every file in it. Path-level read restrictions don't exist on GitHub (see can you restrict access to folders in a GitHub repository?), and sparse checkout doesn't help because the objects are still in the clone (details).

The options are to keep the agent in a separate repository that lacks the sensitive code, or to give it a filtered view of the main one. The broader threat model, including contractors who run their own agents, is in protecting source code from AI coding agents and contractors.

How Gitfence scopes agents

Gitfence sits in front of GitHub and gives each person and each agent a view of the repository with only what they're allowed to see. An agent belongs to a person and never has more access than that person. You set per folder or file: No access, Types only (generated TypeScript declarations with literal values redacted), Can read or Can edit.

The agent gets:

  • A plain git clone containing only permitted paths. Hidden objects are never in the served repository.
  • An AGENTS.md / CLAUDE.md section injected into the view, explaining what's fenced, how to run tests, how to request access, and not to recreate or stub fenced code.
  • An agent token with an optional expiry, used as the git password and as the MCP bearer token. Agent tokens can never use admin APIs.
  • Push checks on every changed path, with rejection messages written so an agent can act on them. Accepted pushes become GitHub pull requests opened on behalf of the agent and its person.
  • An MCP server with these tools: list_repos, fence_status, check_paths, request_access, my_access_requests, run_tests, my_pull_requests, pull_request_status, reply_to_review, list_issues, get_issue, comment_on_issue and create_issue.

run_tests runs the suite in Fenced CI: the real code, in a sandbox with no network access, with hidden source redacted from output (or only a pass/fail verdict in summary mode). That's what lets an agent test code that depends on modules it can't see.

Connecting the MCP server

Replace the URL with your Gitfence server and export your agent token as GITFENCE_TOKEN. These snippets follow each client's MCP documentation; check your client version's docs for exact keys.

Claude Code:

claude mcp add --transport http gitfence https://gitfence.dev/mcp \
  --header "Authorization: Bearer $GITFENCE_TOKEN"

Codex (~/.codex/config.toml):

[mcp_servers.gitfence]
url = "https://gitfence.dev/mcp"
bearer_token_env_var = "GITFENCE_TOKEN"

Cursor (.cursor/mcp.json):

{
  "mcpServers": {
    "gitfence": {
      "url": "https://gitfence.dev/mcp",
      "headers": { "Authorization": "Bearer ${env:GITFENCE_TOKEN}" }
    }
  }
}

What happened in a test run

We gave Claude Code (in a sandbox, with only its clone, an agent token and the MCP server) a task to add a checkout feature using an existing pricing module that was Types only. It called fence_status, read the generated declarations and AGENTS.md, wrote the feature and tests, pushed a branch, and ran the suite with run_tests (7 passing). It didn't stub or recreate the hidden module, and none of the pricing constants appeared in any object in its clone.

Limits

  • Gitfence limits what the agent can fetch from now on; it can't retract code an agent already saw.
  • Fenced CI redaction doesn't recognize encoded output such as base64, and exit codes and timing leak a few bits per run. Use summary mode for untrusted work.
  • GitHub only today; Types only covers TypeScript.
  • Agents can ask for time-limited access (request_access takes a duration such as "2h") or access tied to a Linear or Jira ticket that ends when the ticket closes. These integrations are tested offline, not yet against live Linear or Jira.

Agents are never counted or capped: you pay only for restricted people, and your own team's agents are free. See pricing and Gitfence for AI agents.

A least-privilege setup, in order

  1. Give the agent its own token with an expiry, never your personal credentials.
  2. Give it a working copy without the code it doesn't need.
  3. Make CI config and build scripts read-only for it.
  4. Turn on the agent's sandbox with network off or allowlisted.
  5. Add deny rules for secrets and protected paths as a second layer.
  6. Run its tests where there's no network and no secrets.
  7. Review its changes as pull requests.

FAQ

Can Claude Code read files outside the project directory?

By default its read-only tools work within the working directory and directories you add, and you can deny paths with rules. Commands and scripts it runs can read anything the user account can, unless you enable the sandbox.

Does the Codex sandbox stop it from reading secrets in my repo?

The sandbox restricts writes and network access. Files inside the workspace are readable, so secrets in the repository are readable too.

Is .cursorignore enough to protect a folder from Cursor's agent?

No. Cursor's documentation says the Agent's terminal and MCP tools can still access ignored files. Use it to reduce noise and accidental reads.

Should each AI agent have its own token?

Yes. Separate, expiring tokens let you see which agent did what, revoke one without affecting others, and limit damage if a token leaks.

Can an agent request more access when it needs it?

With Gitfence, an agent can call request_access with a path, access level and reason. That records a pending request; an admin approves or denies it, and the agent can check the result with my_access_requests.

Fence your first repository in minutes

Free for one repository and your own team. Add a restricted person and Pro is free for 14 days, no card.