Claude Code Permissions Guide: A Safe settings.json for Beginners
Set up Claude Code permissions safely with a copy-ready settings.json, three use cases, and a tested Node.js check.
You ask Claude Code to run a test, but an approval dialog appears for every command. Then you allow all of Bash to save time and realize that the same rule could cover a force push or a destructive delete.
You do not have to choose between constant prompts and unrestricted access. A practical starting point is to auto-approve reads and tests, ask before edits and external actions, and deny access to secrets and destructive commands. Those three layers live in settings.json.
Key takeaways
- Rules are evaluated in this order: deny → ask → allow. A more specific allow rule does not override a matching deny or ask rule.
- Project reads are already prompt-free by default. Allow only inspected test commands, ask before edits, external access, or pushes, and deny secrets and destructive actions.
Bash(git *)is too broad for most repositories. It also matches commands such asgit reset --hardandgit push --force.Read(.env)does not stop every child process from opening that file. Use the sandbox as well when you need OS-level isolation.- After changing the file, use
/permissionsand/statusto check which rules and settings sources are active.
What Claude Code can handle, and what a person should decide
| Let Claude Code handle | Require human approval | Always block |
|---|---|---|
| File search, diff review, tests | File edits, commits, pushes, dependency installation | Secret reads, force pushes, hard resets, bulk deletion |
Read, Grep, git diff | Edit, git commit, npm install | .env, git push --force, git reset --hard, rm -rf |
Anything that is hard to reverse, sends data outside the machine, or touches credentials should stay in ask or deny.
Start with this settings.json
Create .claude/settings.json at the repository root and start with the following team-safe baseline.
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"defaultMode": "default",
"allow": [
"Bash(npm test *)",
"Bash(npm run lint *)"
],
"ask": [
"Edit",
"WebFetch",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(git push *)",
"Bash(git clean *)",
"Bash(git restore *)",
"Bash(npm install *)",
"Bash(npm uninstall *)"
],
"deny": [
"Read(.env)",
"Read(.env.*)",
"Read(**/secrets/**)",
"Edit(.env)",
"Edit(.env.*)",
"Edit(**/secrets/**)",
"Bash(git push --force *)",
"Bash(git reset --hard *)",
"Bash(rm -rf *)",
"Bash(rm *)",
"PowerShell(Remove-Item *)"
]
}
}
This baseline assumes you have inspected the repository’s package.json scripts. In an unfamiliar repository, leave allow empty until you know what the test command executes. Bash(npm test *) matches both npm test and forms with trailing arguments.
Where settings.json belongs
| Scope | Location | Use it for |
|---|---|---|
| User | ~/.claude/settings.json | Defaults shared by all of your projects |
| Project | .claude/settings.json | Team rules committed to Git |
| Local | .claude/settings.local.json | Personal settings for this machine; do not commit it |
| Managed | Settings distributed by an administrator | Organization rules that users cannot override |
The settings precedence is Managed, command line, Local, Project, then User. Array settings such as permissions.allow are concatenated across scopes rather than replaced wholesale. A matching deny is still evaluated before ask and allow. Put shared safeguards in Project settings and non-negotiable policy in Managed settings.
How to read allow, ask, and deny rules
| Rule | Meaning |
|---|---|
Read | Matches every built-in read; a bare allow is normally unnecessary for files inside the project |
Bash(npm test) | Matches exactly npm test |
Bash(npm test *) | Matches npm test with or without trailing arguments |
Bash(ls*) | Matches ls -la, but also lsof, so it is broader than it looks |
Read(//Users/me/secrets/**) | Matches an absolute filesystem path |
Edit(/src/**/*.ts) | In Project settings, matches files below the repository’s src directory |
WebFetch(domain:docs.anthropic.com) | Matches WebFetch requests to that domain |
Bash(git *) also covers git push origin main and git reset --hard. Allow individual safe commands instead of the whole command family.
Why Read and Edit cannot fully protect secrets
Paths in Read and Edit rules follow gitignore-style matching.
| Pattern | Anchor | Example |
|---|---|---|
//path | Filesystem root | Read(//Users/me/secrets/**) |
~/path | Home directory | Read(~/.ssh/**) |
/path | Location associated with the settings source | In Project settings, Edit(/src/**) targets the repository’s src directory |
path or ./path | Current working directory | Read(.env) |
A single leading slash is not an absolute filesystem path in a Read or Edit rule. More importantly, these rules cover Claude Code’s built-in file tools and recognized file commands. They do not stop an arbitrary Node.js or Python child process from opening a file directly.
If the repository handles credentials, combine these rules with the Claude Code approval and sandbox guide so the operating system also limits child processes. The sandbox runs on macOS, Linux, and WSL2, not native Windows; use WSL2 or an isolated container there and retain PowerShell deny rules.
Three use cases
Use case 1: Automate tests in a personal project
Input: source files, tests, and the Git diff. Output: a proposed fix and test results. Human decision: edits, dependency changes, commits, and pushes.
Start with the baseline configuration above and leave edits in ask. Move a command to allow only after you have seen it run repeatedly without changing external state.
Use case 2: Share blocked operations with a team
Input: the commands the team needs and the operations it never wants automated. Output: a Git-managed permission policy. Human decision: new deny rules and exceptional maintenance work.
Keep the .env, force-push, hard-reset, and recursive-delete rules in Project settings. Move rules that team members must not change into Managed settings.
Use case 3: Investigate a production repository without editing it
Input: incident logs and Git history. Output: likely causes and a remediation plan. Human decision: edits, deployment, and any external communication.
Start the session in Plan mode:
claude --permission-mode plan
If a write becomes necessary, switch to an isolated worktree or disposable environment before approving it.
Four concrete failure cases
| Failure | Why it happens | Fix |
|---|---|---|
Allowing Bash(git *) | The same pattern covers push and hard reset | Allow only commands whose side effects you have inspected |
Adding allow: Bash(aws s3 ls) under deny: Bash(aws *) | Deny wins before ask and allow; specificity creates no exception | Narrow the deny rule or separate the safe operation behind another command boundary |
Treating Read(.env) as an OS boundary | Read/Edit rules do not stop arbitrary Node.js or Python subprocesses | Add sandbox denyRead or credential rules |
| Removing a Local allow but seeing it remain | Permission arrays concatenate across User, Project, and Local scopes | Inspect rule sources in /permissions and loaded scopes in /status |
Read the Claude Code security failure cases for incident patterns and the security best practices for a broader rollout checklist.
Choosing a permission mode
| Mode | Good fit | Important limit |
|---|---|---|
default | A repository you are still learning | Prompts when approval is required |
acceptEdits | Development where the edit scope is already understood | File edits and common filesystem operations can be auto-approved |
plan | Investigation, design, and read-only production review | Does not edit source files |
auto | Trial use of background safety checks | Auto-approves calls judged to align with the request; verify the current release behavior |
dontAsk | Unattended work limited to pre-approved operations | Denies unapproved tools instead of opening a prompt |
bypassPermissions | A disposable container or VM | Do not use it on a normal workstation or production host |
With sandboxing enabled, sandbox.autoAllowBashIfSandboxed defaults to true. Sandboxed Bash commands may therefore run without the whole-tool Bash prompt. Content-scoped ask rules such as Bash(git push *) still prompt, explicit deny rules still apply, and Plan mode keeps its own restrictions.
Pitfall: using a broad allow rule and relying on one hook
Allowing all of Bash and expecting a PreToolUse hook to catch every destructive variant turns one hook into the only safety boundary. A misplaced hook or an incomplete pattern can then expose the entire command surface.
Cause: the allowed command set is broad, while the dynamic check is the only control.
Fix: write explicit deny rules and narrow allow rules first. Use hooks only as an additional layer for decisions that genuinely depend on runtime state. A hook’s allow result does not override a matching deny or ask rule.
Copy-ready configuration check
The following script verifies that .claude/settings.json is valid JSON and contains four minimum deny rules.
// scripts/check-claude-permissions.mjs
import { readFileSync } from "node:fs";
const path = ".claude/settings.json";
const settings = JSON.parse(readFileSync(path, "utf8"));
const deny = new Set(settings.permissions?.deny ?? []);
const required = [
"Read(.env)",
"Edit(.env)",
"Bash(git push --force *)",
"Bash(git reset --hard *)",
"Bash(rm *)",
"PowerShell(Remove-Item *)",
];
const missing = required.filter((rule) => !deny.has(rule));
if (missing.length > 0) {
console.error(`Missing deny rules: ${missing.join(", ")}`);
process.exit(1);
}
console.log("Minimum permission check: OK");
node scripts/check-claude-permissions.mjs
This is not proof that a configuration is safe. It is a small CI guard that detects when a minimum deny rule disappears.
When the settings appear not to work
- Open
/permissionsand inspect each rule and its source file. - Run
/statusand check which settings scopes were loaded. - Recheck spaces and anchors such as
Bash(ls *)versusBash(ls*), and/pathversus//path. - Check sandbox auto-approval and any
denyoraskrule from a higher-precedence source. - Move rules the team needs back into
.claude/settings.jsoninstead of leaving them as temporary CLI choices.
Summary
Create .claude/settings.json, paste the baseline, and inspect it with /permissions. Keep only inspected tests in allow, edits and external actions in ask, and secrets and destructive actions in deny. Expand automatic access one reviewed command at a time.
For a repository-ready permission template and rollout checklist, use the Claude Code product guides as the single next step.
Official references
- Configure permissions
- Claude Code settings
- Choose a permission mode
- Configure the sandboxed Bash tool
- Debug your configuration
- Security
- Hooks reference
What was actually tested
On July 22, 2026, the JSON block in all ten locales was parsed with JSON.parse, and the Node.js checker ran in a temporary project. With all six required deny rules present, it exited with code 0. Removing Bash(git reset --hard *) produced code 1 and named the missing rule. This detects configuration drift; it is not evidence from production or proof that a policy is secure. Verify active behavior with /permissions and /status.
Related Posts
Recover from Claude Code Permission Denials Without Weakening Your Guardrails
Turn a denied Claude Code command into a safe recovery prompt with reason, alternative action, proof commands, and retry criteria.
Claude Code Permission Safety Ladder: Expand Access Without Losing Control
A beginner-friendly ladder for moving Claude Code from read-only to limited edits, proof commands, and deploy checks.
Claude Code Permission Budget Loop: Check Permissions, Cost, and Logs in 5 Minutes
A practical Claude Code loop for allow/deny rules, cost limits, execution logs, and team handoff.
Free PDF: Claude Code Cheatsheet
Enter your email and download the one-page Claude Code cheatsheet for commands, review habits, and safe workflows.
We handle your data with care and never send spam.
Level up your Claude Code workflow
Start with the free PDF, use Gumroad guides when you need repeatable workflows, and book consultation when rollout or revenue paths need human judgment.
About the Author
Masa
Engineer focused on practical Claude Code workflows. Runs claudecode-lab.com, a 10-language technical media site.
Related Products
The Complete Claude Code Setup & Configuration Guide
From install to team-ready workflow.
A practical guide to installation, CLAUDE.md, hooks, MCP servers, permissions, IDE setup, and CI/CD workflows.
Claude Code Quick Reference Cheatsheet
A free one-page reference for daily Claude Code work.
Keep the essential commands, file-reference patterns, CLAUDE.md reminders, prompting habits, review cues, and debugging workflow notes next to your editor.