How to Lock Down Claude Code


Claude Code is useful when it has access to your project, but it should not have unrestricted access to the rest of your computer. Here is how I set up a deny-by-default configuration.


I often work with sensitive research data, which I do not want to be touched by an AI agent. Claude Code is genuinely useful, but giving it access to all files and unrestricted network access by default is the wrong trade for that risk.

So, I decided to lock down Claude Code: close everything off first and then open only what each project actually needs. I put my configuration in the claude-lockdown repository. It is both a reproducible recipe and a small working example with synthetic R, shell, CSV and Quarto files. You can clone it without exposing any real data.

In this post, I will show the main idea behind this setup and how to use it for your own projects.

Why lock down Claude Code?

Claude Code can read files, edit them and run commands. This is what makes it so useful. But it also means that a mistaken instruction can read the wrong folder, remove a file, upload something with curl, or push an unfinished change to a remote repository.

I do not think the answer is to avoid AI coding tools. I want Claude Code to work inside a project folder, run the scripts I use, install packages from the expected registries and help me write code. I just do not want it to have access to my whole home directory because one project needs access to only one folder.

The basic principle is simple:

  1. Deny access to sensitive places globally.
  2. Define one trusted parent folder for projects.
  3. Add a small project-level configuration for commands, network domains and folders that need extra protection.

This is much easier to reason about than trying to remember what Claude Code can access in every new project.

Global configuration

The first step is to copy global-settings.json to ~/.claude/settings.json and adjust it for your computer. The file looks roughly like this:

{
  "permissions": {
    "deny": [
      "Read(~/Desktop/**)",
      "Read(~/Documents/**)",
      "Read(~/Downloads/**)",
      "Bash(rm *)",
      "Bash(sudo *)",
      "Bash(git push *)"
    ]
    "allow": ["Edit(~/Projects/**)"]
  },
  "sandbox": {
    "enabled": true,
    "filesystem": {
      "denyRead": ["~/", "/Volumes"],
      "allowRead": ["~/Projects"]
    },
    "network": { "strictAllowlist": true }
  }
}

I keep my projects in ~/Projects, so this is the one part of my home folder that I intentionally make available. Other folders, such as Desktop, Documents, Downloads, Library, OneDrive, Pictures and Public, are denied explicitly. The configuration also denies the obvious dangerous commands, including rm, sudo and git push.

Do not use one large rule such as Read(~/**) and expect a project configuration to reopen one directory below it. Claude Code’s Read, Edit and Write permissions give deny rules priority over allow rules. In other words, a more specific project allow rule cannot undo a matching global deny rule.

This is why I deny home folders one by one and leave the trusted parent folder unmentioned. Claude Code can work in ~/Projects, but it cannot read all the other folders.

The Bash sandbox is slightly different. It has its own filesystem settings, where a more specific allow rule can reopen a project folder. The distinction is important: the permission rules control the Read/Edit/Write tools, while the sandbox controls programs launched through Bash. You need to configure both layers.

The global baseline also suppresses Claude’s automatic attribution trailers in commits and pull requests:

"attribution": {
  "commit": "",
  "pr": ""
}

I prefer commits and pull requests to contain only the messages I decide to add. You can remove these two options if you want Claude Code to add its attribution trailers.

It also strips select credential environment variables, like ANTHROPIC_API_KEY and GITHUB_TOKEN, out of the Bash environment, so a command that is otherwise allowed still cannot casually echo them.

After you copy and edit the file, validate the JSON:

python3 -m json.tool ~/.claude/settings.json > /dev/null && echo valid

Then fully quit and restart Claude Code. A running session may not pick up a newly copied global settings file.

Configure every project only for what it needs

Projects have to live inside the trusted folder from step one. Copy project-settings-template.json to each project’s subfolder <project>/.claude/settings.json and work through the placeholders:

{
  "permissions": {
    "defaultMode": "acceptEdits",
    "allow": [
      "Bash(conda activate PROJECT_ENV_NAME)",
      "Bash(Rscript R/*.R)"
    ],
    "deny": ["Bash(git add *)", "Bash(git commit *)", "Edit(data/**)"]
  },
  "sandbox": {
    "filesystem": { "denyWrite": ["data"] },
    "network": { "allowedDomains": ["cran.r-project.org", "conda.anaconda.org"] },
    "excludedCommands": ["quarto *"]
  }
}

Swap PROJECT_ENV_NAME for your actual conda environment name, spelled out rather than a wildcard, or the rule silently won’t match. Point the Bash allow rules at your project’s actual scripts. Add whatever domains your toolchain needs: PyPI, CRAN, a conda channel. And notice the data folder is protected twice: Edit(data/**) stops the Edit tool, but only sandbox.filesystem.denyWrite stops the Bash tool from writing there too. You need both, because they’re different enforcement layers.

The project file is not another copy of the global lockdown. It only adds what is necessary for that project. For example, the worked example in the repository allows an R pipeline, selected shell scripts and a specifically named conda environment:

"allow": [
  "Bash(Rscript R/*.R)",
  "Bash(bash scripts/*.sh)",
  "Bash(conda activate cpc_demo)"
]

Do not replace cpc_demo with a wildcard. Name the environment that the project really uses. The same applies to scripts: allow bash scripts/run_pipeline.sh or a small pattern for scripts in one folder, not every possible command on your computer.

This may sound restrictive, but after the initial configuration Claude Code works normally for the usual project tasks. It is also a good record of how the project is supposed to be run.

Limit network access (optional)

The configuration uses Claude Code’s sandbox network allowlist. For the R and conda example, it permits only the domains needed to obtain packages:

"allowedDomains": [
  "conda.anaconda.org",
  "repo.anaconda.com",
  "anaconda.org",
  "cran.r-project.org"
]

This means a command such as curl https://example.com is refused by the sandbox, while requests to the package repositories can work. For another project, you may need PyPI, npm or an internal package registry instead. Add only the actual domains you need.

I prefer this to a general curl or wget deny rule. The network allowlist is a stronger boundary because it also applies to other programs that try to connect to an unapproved host.

Keep important project data read-only

In my bioinformatics projects, the input data/ folder should not be modified. A useful extra rule is to deny both the editing tools and Bash writes:

"deny": ["Edit(data/**)"],
"filesystem": {
  "denyWrite": ["data"]
}

The two rules are needed. Edit(data/**) stops Claude Code’s Edit and Write tools, but Bash can still create files unless denyWrite is set too. With the second rule, Python, R and shell scripts are all stopped at the sandbox level if they try to write under data/.

Test the configuration

Do not just trust that a security configuration works. Start a fresh Claude Code session outside your trusted parent folder and try some harmless tests:

ls ~/Desktop
sudo whoami
curl https://example.com
git push

The folder read, sudo and git push should be refused. curl should be refused by the sandbox network layer if example.com is not on the allowlist.

Then open a session inside a configured project. Its allowed script should run, while a Git operation, a write in data/, and an unlisted network destination should be blocked. The repository includes two complete copy-and-paste test scenarios, including expected results, for precisely this purpose.

Testing is useful because it reveals small details that are easy to miss. For example, a cache directory may need both read and write permission. Conda also needs ~/.conda writable when it creates an environment, not only the conda installation directory.

To perform the full set of tests, follow the instructions at claude-lockdown repository.

A few important limitations

This setup is a practical safeguard, not a magic guarantee. The Bash(rm *) deny rule catches the normal rm command, but it cannot prevent a program such as Python from deleting a file inside an otherwise writable project folder. If a directory must not be changed, use the path-specific sandbox.filesystem.denyWrite rule.

For ordinary deletion in a project, I use the repository’s trash.sh helper. It moves a file into a visible trash/ folder instead of removing it permanently. You cannot allow rm in one project while denying it globally because deny rules always win, so an explicit reversible helper is a better solution.

Some programs may not run in the macOS sandbox. The repository documents Quarto as one example. Claude Code has an excludedCommands escape hatch for this, but it drops all sandbox protection for the excluded command. I use it only when I understand why the program fails and there is no safer option.

Finally, do not rely only on Automatic mode. Auto and Manual mode are selected in the Claude Code application, not in the settings file. Both modes still respect explicit denies and the sandbox, which is why the configuration itself is the important part.

Final thoughts

Locking down Claude Code did not make it less useful for me. It made the boundary clear: Claude Code can work on the project I opened, but it should not silently gain access to everything else on my computer.

This post is only an overview. The claude-lockdown repository contains the complete, ready-to-copy configuration, project template and the exact test scenarios. Clone it, copy the global baseline to ~/.claude/settings.json, adapt the trusted folder names for your computer, then use the template in every project and run both test scenarios. This way you can confirm the lockdown works on your own computer before trusting it with real data.

If you have any questions or suggestions, feel free to email me.

Written on September 12, 2026