How to Restrict and Manage Claude Code File System Permissions Effectively
A security-focused guide to sandboxing Claude Code with deny rules, OS-level filesystem isolation, and managed settings — so the 93% approval fatigue rate stops being your last line of defense.
How to Restrict and Manage Claude Code File System Permissions Effectively
Claude Code gives you a three-layer model to restrict file system access: a permission system (allow/ask/deny rules in settings.json), an OS-level sandbox (filesystem and network isolation for Bash commands), and managed settings (enterprise-enforced policies that override individual configs). The most effective setup combines all three — deny rules that block access to .env files and SSH keys, a sandbox that prevents Bash subprocesses from escaping the working directory, and a CLAUDE_CODE_SUBPROCESS_ENV_SCRUB flag that strips cloud credentials from every subprocess — so even if a prompt-injection attack tricks the agent into running a shell command, the blast radius stays inside the project folder.
Why this matters now: Anthropic's own engineering data shows that users approve 93% of permission prompts, and experienced users auto-approve over 40% of sessions. When humans rubber-stamp nearly every request, the interactive permission prompt is not a meaningful security control — it is a performance. The real defense has to live in the configuration, not in the person clicking "yes."
Why File System Permissions Are the Critical Attack Surface
Claude Code runs with the same filesystem permissions as the developer who invokes it. The agent can read any file your user can read, edit anything your user can write, and execute any binary on your $PATH. Three 2026 incidents show what happens when that power is left ungoverned:
- Poisoning Claude Code (June 2026): Security researcher RyotaK demonstrated that a single malicious GitHub issue could hijack repositories through Claude Code's GitHub Action, exfiltrating secrets and modifying code. Anthropic patched it in
claude-code-actionv1.0.94, paid a $4,800 bug bounty, and rated it CVSS 7.8 (Cloud Security Alliance research note, June 2026). - Clinejection (February 2026): The Cline AI coding tool's automated issue triage was vulnerable to prompt injection through issue titles. A single crafted GitHub issue gave attackers a four-step path from injection to credential theft (Adnan Khan, February 2026).
- Prompt-injection defense bypass (arXiv 2601.17548v1, 2026): A meta-analysis of 31 attack techniques found that adaptive attacks bypass leading detection systems at rates of 78–93%. Protect AI was bypassed 93% of the time, PromptGuard 91%, and PIGuard 89% under adaptive attack conditions.
The pattern is clear: the agent's filesystem access is the prize, and interactive approvals do not reliably stop the attack. You need static, machine-enforced boundaries.
The Three-Layer Permission Model
Claude Code's security architecture is not a single knob — it is three independent layers that reinforce each other:
- Permission system (
settings.json): Evaluates every tool call — Bash, Read, Edit, WebFetch, MCP tools — before it runs. Rules are checked in order: deny first, then ask, then allow, and the first match wins. A deny rule blocks a call even if a broader allow rule would match. - OS-level sandbox: Enforces filesystem and network isolation at the kernel level for Bash commands and their child processes. On macOS it uses the built-in Seatbelt framework; on Linux and WSL2 it uses
bubblewrap+socat. The sandbox does not govern Claude's built-in Read/Edit/Write tools — those are controlled by the permission system. - Managed settings: Enterprise-level policies stored in
/Library/Application Support/ClaudeCode/managed-settings.json(macOS) or the equivalent Linux path. These have the highest precedence and cannot be overridden by project or user settings, making them the enforcement mechanism for organizational security policies.
Settings precedence, from highest to lowest: managed settings → .claude/settings.json (project, shared) → .claude/settings.local.json (project, personal) → ~/.claude/settings.json (user, all projects).
Step-by-Step: Locking Down File System Access
1. Deny access to secrets and credentials
Start with a project-level .claude/settings.json that blocks the files an agent should never touch:
{
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/)",
"Read(./**/*.pem)",
"Read(./**/*.key)",
"Edit(./.env)",
"Bash(cat .env)",
"Bash(cat ~/./.ssh/)",
"Bash(curl:)"
]
}
}
Important caveat: a Read deny covers Claude Code's built-in file tools (Read, Grep, Glob, LS), but a Python or Node script run through Bash can still open the file directly because that read happens in the shell, not through Claude's Read tool. That is why you pair the Read deny with a Bash deny on cat, head, and tail for those paths.
2. Enable the sandbox for Bash isolation
Run /sandbox in a Claude Code session and select auto-allow mode so sandboxed commands run without prompting but within OS-enforced boundaries. To enable it across all projects, set this in ~/.claude/settings.json:
{
"sandbox": {
"enabled": true,
"filesystem": {
"denyRead": ["~/"],
"allowRead": ["."],
"denyWrite": ["~/", "/etc/", "/usr/"],
"allowWrite": ["."]
}
}
}
This restricts Bash commands to the working directory. The denyRead on ~/ blocks access to your home directory, while allowRead on . opens the project folder. Note the merging behavior: allowRead beats denyRead, so if you add a directory to both lists, the allow wins. Keep deny lists specific and allow lists narrow.
3. Scrub credentials from subprocesses
Sandboxed Bash commands inherit the parent process environment by default — including any AWS_SECRET_ACCESS_KEY, DATABASE_URL, or ANTHROPIC_API_KEY set in your shell. Two settings address this:
"sandbox": { "credentials": ["AWS_SECRET_ACCESS_KEY", "DATABASE_URL"] }— unsets or masks specific variables for sandboxed commands.CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=true(environment variable) — strips all Anthropic and cloud provider credentials from every subprocess, not just sandboxed ones.
Set the scrub flag globally in your shell profile so it applies to every session.
4. Block network exfiltration paths
Without network isolation, a compromised agent can exfiltrate sensitive files like SSH keys. Configure the sandbox network layer:
{
"sandbox": {
"network": {
"allowedDomains": ["registry.npmjs.org", "github.com", "pypi.org"]
}
}
}
Also evaluate the allowUnixSockets setting carefully. Granting access to /var/run/docker.sock effectively gives the agent host-level access through the Docker socket. Unless you have a specific need, leave Unix sockets blocked — the optional seccomp filter (installed via npm install -g @anthropic-ai/sandbox-runtime) enforces this on Linux.
5. Enforce sandboxing as a hard gate
By default, if the sandbox cannot start (missing dependencies, unsupported platform), Claude Code shows a warning and runs commands without sandboxing. For managed deployments, flip this to a hard failure:
{
"sandbox": {
"failIfUnavailable": true
}
}
This ensures no Bash command runs without OS-level isolation. Pair it with managed settings so individual developers cannot disable the sandbox.
Common Mistakes That Undo Your Permissions
- Allowing
Read(/)on a personal machine. This grants the model read access to every file your user can see —~/.ssh,~/.aws, browser cookies, everything. Scope reads to the workspace only. - Allowing edits to dotfiles. The model can enthusiastically "improve" your
~/.zshrcor~/.bashrc, which is a privilege escalation vector. Keep dotfiles out of any allowed edit scope. - Using
--dangerously-skip-permissionsoutside a container. This flag is blocked when running as root on Linux and macOS, but on a regular user account it removes all interactive controls. Only use it inside a disposable, locked-down sandbox with no valuable credentials. - Relying on Bash
allowrules as a security boundary. Bash matching is best-effort, not a hardened shell sandbox. ABash(git:)allow will not match/usr/bin/git statusbecause the prefix is different. For security, rely ondenyrules plus a restricted environment. - Forgetting that
allowReadbeatsdenyRead. Sandbox filesystem rules merge across scopes. If you deny reads to~/at the user level but allow reads to~/at the project level, the allow wins. Audit your merged configuration with the/sandboxpanel's Config tab.
Enterprise Governance Patterns
For teams scaling Claude Code across dozens of developers, the configuration-level controls need organizational enforcement. TrueFoundry's June 2026 enterprise governance guide recommends treating Claude Code deployment as an infrastructure decision, not a configuration afterthought:
- Managed settings as policy: Store deny rules, sandbox configuration, and
failIfUnavailable: truein the managed settings file so they cannot be overridden by project or user settings. - Audit trails: Log every tool call — what was requested, what was denied, what was allowed. Claude Code's hooks system can post permission decisions to a SIEM or log aggregator in real time.
- Never run as root: A sandboxed Claude Code running as root defeats the sandbox entirely. Ensure developers run under their own user accounts with minimum required filesystem permissions.
- Secrets in vaults, not
.envfiles: If a secret matters, it should never be in a plaintext file the agent can read. Use a secrets manager and inject credentials at runtime, not at rest.
What You Should Do Today
- Audit your current
settings.json— check whether.env,.ssh, and credential files are explicitly denied. - Enable the sandbox via
/sandboxand setsandbox.enabled: truein your user settings. - Set
CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=truein your shell profile to scrub cloud credentials from all subprocesses. - Create a managed settings file if you are responsible for a team — enforce deny rules and
failIfUnavailable: trueorganization-wide. - Test your configuration — ask Claude to read
.env(should be blocked), write to/tmp(should be blocked by sandbox), and fetch from an unapproved domain (should be denied).
The goal is not to slow down development. It is to make the security boundary static and machine-enforced so the 93% approval rate stops mattering — because the dangerous actions are blocked before the prompt ever appears.
If you need help setting up Claude Code permissions and sandboxing for your team, ishchuk.eu offers AI automation consulting with hands-on security configuration. Book a session to get a validated, team-ready setup.
Frequently asked questions
- How do I restrict Claude Code from reading sensitive files like .env?
- Add a Read deny rule in your .claude/settings.json file using the permissions.deny array, such as Read(./.env) and Read(./secrets/). This blocks Claude's built-in file tools from reading those paths. Because a Bash command like cat can still read the file through the shell, also add Bash deny rules for cat, head, and tail on those paths. Enable the OS-level sandbox to enforce filesystem isolation at the kernel level for all Bash commands and their child processes.
- What is the difference between Claude Code permissions and the sandbox?
- Claude Code permissions are rules in settings.json that evaluate every tool call before it runs, covering Bash, Read, Edit, WebFetch, and MCP tools. The sandbox provides operating-system-level filesystem and network isolation that applies only to Bash commands and their child processes. The built-in Read, Edit, and Write file tools are governed by the permission system, not the sandbox. Effective security uses both layers: permissions for all tools and the sandbox for shell command isolation.
- Why do users approve 93% of Claude Code permission prompts?
- Anthropic's own engineering data shows users approve 93% of permission prompts, creating approval fatigue where people stop reading what they are approving. Experienced users auto-approve over 40% of sessions. This means interactive permission prompts are not a reliable primary security control at scale. The solution is to enforce security through static configuration: deny rules, OS-level sandboxing, and managed settings that block dangerous actions before a prompt ever appears.
- How do I scrub API keys from Claude Code subprocesses?
- Set the CLAUDE_CODE_SUBPROCESS_ENV_SCRUB environment variable to true in your shell profile. This strips Anthropic and cloud provider credentials from all subprocesses Claude Code spawns. For more targeted control, use the sandbox.credentials setting in settings.json to unset or mask specific variables like AWS_SECRET_ACCESS_KEY or DATABASE_URL for sandboxed Bash commands only.
- Can Claude Code sandbox be enforced for an entire team?
- Yes. Use managed settings stored in the managed-settings.json file, which has the highest precedence and cannot be overridden by project or user settings. Set sandbox.enabled to true and sandbox.failIfUnavailable to true so the sandbox is mandatory and any failure to start it is a hard error. This ensures every developer on the team has OS-level filesystem and network isolation enforced automatically with no option to disable it locally.