클로드 코드 권한 설정
클로드 코드를 쓰다 보면 가장 자주 마주치는 것이 “이 명령어를 실행해도 될까요?”라는 권한 요청 팝업입니다. 처음에는 안전장치로 느껴지지만 매번 답하다 보면 꽤 성가시죠. 이 글에서는 클로드 코드의 권한 시스템을 속속들이 파헤쳐서 안전하면서도 흐름이 끊기지 않는 환경을 만드는 방법을 알아보겠습니다.
권한 시스템의 기본 구조
클로드 코드는 도구 종류에 따라 세 단계의 기본 권한 정책을 적용합니다.
| 도구 유형 | 예시 | 승인 필요 | ”다시 묻지 않기” 범위 |
|---|---|---|---|
| 읽기 전용 | 파일 읽기, Grep, Glob | 없음 | — |
| 파일 수정 | Edit, Write | 있음 | 세션 종료 시까지 |
| Bash 명령어 | 셸 실행 | 있음 | 프로젝트 디렉토리 + 명령어 단위로 영구 |
읽기 전용 도구는 별다른 확인 없이 바로 사용할 수 있고, Bash 명령어는 한 번 허용하면 같은 프로젝트에서 같은 명령어에 한해 영구적으로 허용됩니다. 파일 수정은 세션이 끝나면 다시 물어보죠.
승인이 필요한 도구를 처음 실행하면 이런 팝업이 뜹니다.
⏺ Web Search("웹 개발 한국어 학습 자료 2026")
───────────────────────────────────────────────────────
Tool use
Web Search("웹 개발 한국어 학습 자료 2026")
Claude wants to search the web for: 웹 개발 한국어 학습 자료 2026
Do you want to proceed?
❯ 1. Yes
2. Yes, and don't ask again for Web Search commands in /Users/dale/our-cc
3. No
Esc to cancel · Tab to amend
1번은 이번 한 번만 허용, 2번은 현재 프로젝트에서 해당 도구를 영구 허용(settings.json에 저장), 3번은 거부입니다.
Bash 명령어 중에서도 ls, cat, head, tail, grep, find, wc, diff, stat, du, cd 같은 읽기 전용 명령어는 어떤 모드에서든 승인 없이 실행됩니다.
이 목록은 내장되어 있어서 변경할 수 없지만 특정 명령어에 대해 승인을 요구하고 싶다면 ask나 deny 규칙을 추가하면 돼요.
이 기본 정책만으로도 기본적인 보호는 되지만 프로젝트마다 쓰는 명령어가 다르고 팀마다 보안 요구사항이 다릅니다.
그래서 settings.json의 permissions 설정으로 이 동작을 세밀하게 제어할 수 있어요.
allow, deny, ask 규칙
권한 규칙은 크게 세 가지로 나뉩니다.
{
"permissions": {
"allow": ["자동 허용할 도구와 패턴"],
"ask": ["매번 확인을 거칠 도구와 패턴"],
"deny": ["무조건 차단할 도구와 패턴"]
}
}
평가 순서는 deny → ask → allow입니다. deny에 해당하는 규칙이 있으면 allow에도 있더라도 무조건 차단돼요. 이 규칙은 설정 파일의 레벨과도 무관합니다. 어떤 레벨에서든 deny된 도구는 다른 어떤 레벨의 allow로도 해제할 수 없어요.
현재 적용 중인 권한 규칙은 클로드 코드 안에서 /permissions 명령으로 확인할 수 있습니다.
어떤 규칙이 어느 설정 파일에서 왔는지도 볼 수 있어서 디버깅할 때 유용해요.
설정 파일의 계층 구조
설정 파일은 여러 레벨에 분산됩니다.
| 우선순위 | 범위 | 파일 위치 |
|---|---|---|
| 1 (최고) | 관리자 | OS별 시스템 경로 |
| 2 | CLI 인자 | 명령줄 실행 시 |
| 3 | 로컬 프로젝트 | .claude/settings.local.json |
| 4 | 프로젝트 | .claude/settings.json |
| 5 (최저) | 사용자 | ~/.claude/settings.json |
대부분의 설정은 우선순위가 높은 쪽이 낮은 쪽을 덮어씁니다.
하지만 allow, deny, ask 권한 규칙은 예외예요. 우선순위를 따르지 않고 모든 레벨의 규칙이 하나로 합쳐집니다.
합쳐진 규칙은 deny → ask → allow 순서로 평가됩니다.
예를 들어 사용자 설정에서 Bash(git push *)를 deny하면 로컬 프로젝트 설정에서 allow해도 차단됩니다.
반대도 마찬가지로 프로젝트 설정의 deny는 사용자 설정의 allow를 이겨요.
어느 레벨에 있든 deny가 항상 우선하기 때문이죠.
실무에서 권한을 배치하는 방법은 이렇습니다.
사용자 설정(~/.claude/settings.json)에는 git status, git log처럼 어디서든 안전하게 쓰는 명령어를 허용해두고, 프로젝트 설정(.claude/settings.json)에는 팀에서 합의한 빌드·테스트 명령어 허용과 민감 파일 차단 규칙을 넣습니다.
로컬 프로젝트 설정(.claude/settings.local.json)은 .gitignore에 포함되니까 팀 설정 위에 자기만의 추가 규칙을 올리면 돼요.
권한 외의 설정 옵션(모델 선택, 언어, 환경 변수 등)이 궁금하다면 클로드 코드 설정 가이드를 참고하세요.
권한 모드
allow/deny/ask 규칙 외에 defaultMode 옵션으로 클로드 코드가 도구를 얼마나 자율적으로 실행할지 스펙트럼을 조절할 수 있습니다.
{
"permissions": {
"defaultMode": "acceptEdits"
}
}
default, acceptEdits, plan, auto, dontAsk, bypassPermissions 중에서 선택할 수 있어요.
각 모드의 동작 차이, 전환 방법, 보호 경로, 상황별 추천은 클로드 코드 권한 모드에서 자세히 다루고 있습니다.
bypassPermissions 모드에 대해서는 오해가 많은데요.
권한 평가를 완전히 생략하는 게 아닙니다.
공식 문서에 따르면 이 모드에서도 규칙 평가는 항상 아래 순서로 진행됩니다.
- deny 규칙 체크 — 매칭되면 bypassPermissions 모드라도 즉시 차단
- ask 규칙 체크 — 명시적
ask규칙과 훅은 모드 검사 이전에 평가되어 도구를 차단할 수 있음 - allow 규칙 체크
- 여기까지 통과한 도구만 bypassPermissions가 자동 승인
다시 말해 bypassPermissions는 1~3단계를 모두 통과한 도구의 확인 팝업을 생략하는 것이지, deny나 ask 규칙을 무력화하지는 않습니다.
.env 파일 읽기를 deny 규칙으로 막아뒀다면 bypassPermissions 모드에서도 해당 도구는 차단됩니다.
Bash 명령어 권한
Bash 권한 규칙은 Bash(패턴) 형식으로 작성하고 glob 패턴(*)을 지원합니다.
{
"permissions": {
"allow": [
"Bash(npm run build)",
"Bash(npm run test *)",
"Bash(git commit *)",
"Bash(git * main)",
"Bash(* --version)",
"Bash(* --help *)"
],
"deny": ["Bash(rm -rf *)", "Bash(sudo *)", "Bash(git push *)"]
}
}
와일드카드 *는 명령어의 어느 위치에든 올 수 있습니다.
Bash(git * main)은 git checkout main, git merge main 같은 명령어를 모두 매칭하죠.
여기서 주의할 점이 있습니다.
* 앞에 공백이 있으면 단어 경계를 인식합니다.
Bash(ls *)는 ls -la와 매칭되지만 lsof와는 매칭되지 않아요.
ls로 시작하는 모든 명령어를 매칭하고 싶다면 Bash(ls*)처럼 공백 없이 작성해야 합니다.
:* 접미사도 트레일링 와일드카드와 같은 의미입니다.
Bash(ls:*)는 Bash(ls *)와 동일한 명령어를 매칭해요.
다만 :*는 패턴 끝에서만 인식되고, Bash(git:* push) 같은 중간 위치에서는 콜론이 일반 문자로 취급됩니다.
클로드 코드는 매칭 전에 프로세스 래퍼를 자동으로 벗깁니다.
timeout, time, nice, nohup, stdbuf가 명령어 앞에 붙어 있으면 제거한 뒤 매칭하죠.
그래서 Bash(npm test *)는 timeout 30 npm test에도 매칭돼요.
셸 연산자도 이해합니다.
Bash(safe-cmd *)는 safe-cmd && malicious-cmd 같은 명령어 체이닝에는 매칭되지 않아요.
&&, ||, ;, | 같은 구분자를 인식해서 각 하위 명령어를 독립적으로 매칭하기 때문이죠.
git status && npm test를 “다시 묻지 않기”로 승인하면 전체 복합 명령어가 아니라 npm test에 대한 규칙이 저장됩니다.
Bash 패턴의 한계
Bash 권한 패턴으로 명령어 인자까지 제한하는 건 완벽하지 않습니다.
예를 들어 Bash(curl http://github.com/ *)로 GitHub URL만 허용하려고 해도 이런 변형을 막지 못해요.
# 옵션이 URL 앞에 오는 경우
curl -X GET http://github.com/...
# 프로토콜이 다른 경우
curl https://github.com/...
# 리다이렉트를 이용한 우회
curl -L http://bit.ly/xyz
# 변수를 이용한 우회
URL=http://evil.com && curl $URL
URL을 제한하고 싶다면 Bash에서 curl, wget 같은 네트워크 도구를 deny로 막고 대신 WebFetch(domain:github.com) 규칙으로 특정 도메인만 여는 것이 안전합니다.
파일 읽기·편집 권한
Read와 Edit 규칙은 gitignore 스펙을 따르는 경로 패턴을 사용합니다.
Edit 규칙은 파일을 수정하는 모든 내장 도구에 적용되고, Read 규칙은 Grep이나 Glob 같은 읽기 도구에도 적용됩니다.
| 패턴 | 의미 | 예시 |
|---|---|---|
//경로 | 파일 시스템 절대 경로 | Read(//Users/alice/secrets/**) |
~/경로 | 홈 디렉토리 기준 | Read(~/Documents/*.pdf) |
/경로 | 설정 파일 위치 기준 | Edit(/src/**/*.ts) |
경로 | 현재 디렉토리 기준 | Read(*.env) |
여기서 흔히 하는 실수가 있습니다.
/Users/alice/file은 절대 경로가 아니라 설정 파일 위치 기준의 상대 경로입니다.
절대 경로를 쓰려면 반드시 슬래시 두 개(//Users/alice/file)로 시작해야 해요.
gitignore 패턴에서 *은 단일 디렉토리 내 파일만 매칭하고 **은 재귀적으로 하위 디렉토리까지 매칭합니다.
{
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Read(**/*.pem)",
"Read(**/*.key)"
]
}
}
.env 파일, 시크릿 디렉토리, SSL 인증서 같은 민감한 파일은 이렇게 deny에 넣어두면 실수로 읽히는 것을 막을 수 있습니다.
다만 Read와 Edit deny 규칙은 클로드 코드의 내장 도구에만 적용되고 Bash 하위 프로세스에는 적용되지 않아요.
Read(./.env)를 deny로 막아도 Bash에서 cat .env를 실행하면 읽을 수 있습니다.
OS 레벨에서 모든 프로세스의 접근을 차단하려면 샌드박스를 함께 써야 해요.
심볼릭 링크도 주의가 필요합니다.
allow 규칙은 심볼릭 링크 경로와 대상 경로가 모두 매칭될 때만 허용하지만 deny 규칙은 둘 중 하나만 매칭돼도 차단해요.
예를 들어 Read(./project/**)를 허용하고 Read(~/.ssh/**)를 차단한 상태에서 ./project/key가 ~/.ssh/id_rsa를 가리키는 심볼릭 링크라면 차단됩니다.
WebFetch 권한
WebFetch는 도메인 기반으로 제어합니다.
{
"permissions": {
"allow": [
"WebFetch(domain:docs.anthropic.com)",
"WebFetch(domain:developer.mozilla.org)"
]
}
}
특정 도메인만 allow에 등록하면 그 외의 도메인은 매번 승인을 요청합니다.
deny 없이 allow만 쓰는 게 맞습니다. deny: ["WebFetch"]를 함께 넣으면 allow의 도메인까지 전부 차단되거든요.
다만 WebFetch를 막았다고 네트워크 접근이 완전히 차단되는 건 아니에요.
Bash가 허용돼 있으면 curl이나 wget으로 여전히 외부에 접근할 수 있거든요.
네트워크를 확실히 제한하려면 Bash에서 네트워크 도구를 deny로 막거나 뒤에서 다룰 샌드박스를 함께 쓰는 것이 좋습니다.
MCP 도구 권한
MCP 서버를 연결하면 외부 도구가 클로드 코드 안으로 들어옵니다.
이 도구들도 당연히 권한으로 제어할 수 있는데, mcp__서버이름__도구이름 형식으로 지정합니다.
{
"permissions": {
"allow": ["mcp__github__create_issue", "mcp__github__list_pull_requests"],
"deny": ["mcp__github__delete_repository"]
}
}
서버 단위로 한 번에 제어할 수도 있습니다.
mcp__puppeteer는 puppeteer 서버의 모든 도구를 매칭하고, mcp__puppeteer__*도 같은 의미예요.
여기서 주의할 점은 서버 이름에 점(.)이나 슬래시(/) 같은 특수 문자가 들어가면 밑줄(_)로 치환된다는 겁니다.
예를 들어 claude.ai/Atlassian이라는 원격 MCP 서버의 getConfluencePage 도구를 허용하려면 이렇게 씁니다.
{
"permissions": {
"allow": ["mcp__claude_ai_Atlassian__getConfluencePage"]
}
}
claude.ai/Atlassian이 claude_ai_Atlassian으로 변환된 거죠.
서버 이름이 어떻게 변환되는지 모르겠다면 클로드 코드에서 /mcp 명령을 실행하면 연결된 서버의 정확한 이름과 도구 목록을 확인할 수 있습니다.
실무에서는 읽기 전용 도구만 허용하고 위험한 도구를 차단하는 방식이 효과적입니다.
{
"permissions": {
"allow": [
"mcp__github__list_pull_requests",
"mcp__github__get_issue",
"mcp__github__search_code",
"mcp__sentry"
],
"deny": ["mcp__github__delete_repository", "mcp__github__delete_branch"]
}
}
이렇게 하면 GitHub 서버에서는 조회 관련 도구만 자동 허용하고 삭제 도구는 차단하면서, Sentry 서버의 모든 도구는 허용합니다.
한 가지 더 알아두면 좋은 건 MCP 도구 권한과 MCP 서버 활성화 설정은 별개라는 점이에요.
.mcp.json에 서버를 정의하면 서버가 설치되고, settings.json의 enableAllProjectMcpServers나 enabledMcpjsonServers로 어떤 서버를 로딩할지 결정합니다.
그런 다음 permissions의 mcp__서버이름__도구이름 규칙으로 로딩된 서버의 개별 도구 접근을 제어하는 거죠.
{
"enabledMcpjsonServers": ["github", "sentry"],
"disabledMcpjsonServers": ["experimental-server"],
"permissions": {
"allow": ["mcp__sentry"],
"deny": ["mcp__github__delete_repository"]
}
}
서버를 로딩하지 않으면 도구 자체가 존재하지 않으니 권한 규칙도 적용할 대상이 없습니다. 반대로 서버를 로딩하되 권한 규칙을 따로 설정하지 않으면 기본 권한 모드에 따라 매번 물어보죠. MCP 서버 설정에 대한 자세한 내용은 클로드 코드에서 MCP 서버 연동하기를 참고하세요.
서브 에이전트 권한
클로드 코드의 서브 에이전트도 권한으로 제어할 수 있습니다.
Task(에이전트이름) 형식이에요.
{
"permissions": {
"deny": ["Task(Explore)", "Task(Plan)"]
}
}
특정 서브 에이전트를 비활성화할 때 유용하죠.
CLI에서 --disallowedTools 플래그로도 같은 효과를 낼 수 있고요.
추가 디렉토리 접근
기본적으로 클로드 코드는 실행된 디렉토리만 접근할 수 있습니다. 다른 디렉토리의 파일도 다뤄야 한다면 세 가지 방법이 있어요.
우선 설정 파일에 additionalDirectories를 넣어두면 영구적으로 적용됩니다.
{
"permissions": {
"additionalDirectories": ["../shared-lib/", "../docs/"]
}
}
또는 일회성으로 필요하다면 실행할 때 --add-dir <경로> CLI 인자를 쓸 수 있고, 세션 중에 /add-dir 명령으로 추가할 수도 있어요.
추가된 디렉토리의 파일은 원래 작업 디렉토리와 동일한 권한 규칙을 따릅니다.
모노레포 환경이나 여러 프로젝트를 오가며 작업할 때 유용합니다.
샌드박스와 권한의 관계
클로드 코드 설정 가이드에서도 다뤘지만 샌드박스는 권한과 함께 쓸 때 진가를 발휘합니다. 두 시스템은 서로 다른 계층에서 보안을 담당해요.
권한(Permissions)은 클로드 코드가 어떤 도구를 쓸 수 있고 어떤 파일이나 도메인에 접근할 수 있는지를 제어합니다. Bash, Read, Edit, WebFetch, MCP 등 모든 도구에 적용되죠. 반면 샌드박스(Sandbox)는 OS 레벨에서 Bash 명령어의 파일 시스템과 네트워크 접근을 격리합니다. Bash 명령어와 그 자식 프로세스에만 적용돼요.
이 둘을 함께 쓰면 다층 방어가 됩니다. 권한 deny 규칙은 Claude가 제한된 리소스에 접근하려는 시도 자체를 막고, 샌드박스는 프롬프트 인젝션 같은 공격으로 Claude의 판단이 우회되더라도 Bash 명령어가 정해진 경계 밖으로 나가지 못하게 막아줍니다.
{
"permissions": {
"deny": ["Bash(curl *)", "Bash(wget *)"]
},
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": true,
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"]
}
}
}
autoAllowBashIfSandboxed를 true로 설정하면 샌드박스 안에서 실행되는 Bash 명령은 별도의 권한 확인 없이 자동 허용됩니다.
샌드박스가 시스템을 보호해주니까 권한 팝업 피로를 줄이면서도 안전한 거죠.
Hooks로 권한 확장하기
클로드 코드 Hooks를 사용하면 기본 권한 시스템을 넘어선 커스텀 로직을 적용할 수 있습니다.
PreToolUse 훅은 Claude가 도구를 호출하기 전에 실행되는데, 훅의 종료 코드로 도구 호출을 승인하거나 거부할 수 있어요.
예를 들어 Bash의 glob 패턴 매칭으로는 한계가 있는 URL 검증을 훅에서 처리할 수 있습니다.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -re '.tool_input.command | test(\"curl|wget\") | not' || exit 2"
}
]
}
]
}
}
이 훅은 Bash 명령어에 curl이나 wget이 포함되면 종료 코드 2를 반환해서 실행을 차단합니다.
정규식이나 외부 검증 스크립트를 적용하면 glob 패턴보다 훨씬 정밀한 권한 제어를 구현할 수 있죠.
관리자 설정 (기업용)
기업 환경에서는 IT 관리자가 시스템 레벨의 설정 파일로 조직 전체 정책을 강제할 수 있습니다. 이 설정은 사용자나 프로젝트 설정으로는 절대 덮어쓸 수 없어요.
| OS | 경로 |
|---|---|
| macOS | /Library/Application Support/ClaudeCode/managed-settings.json |
| Linux/WSL | /etc/claude-code/managed-settings.json |
| Windows | C:\Program Files\ClaudeCode\managed-settings.json |
관리자 설정에서만 쓸 수 있는 옵션이 몇 가지 있어요.
disableBypassPermissionsMode—"disable"로 설정하면bypassPermissions모드와--dangerously-skip-permissions플래그를 완전히 차단합니다allowManagedPermissionRulesOnly—true로 설정하면 사용자와 프로젝트 설정에서 allow, ask, deny 규칙 정의가 불가능해집니다. 관리자 설정의 규칙만 적용돼요allowManagedHooksOnly—true로 설정하면 사용자, 프로젝트, 플러그인 훅을 차단하고 관리자 훅과 SDK 훅만 허용합니다
보안 감사를 받아야 하거나 규제 산업에서 일한다면 이 옵션들이 유용할 거예요.
실전 예시
혼자 개발하는 경우라면 사용자 설정에서 자주 쓰는 명령어를 allow에 넣어 팝업을 줄이고 위험한 명령어만 deny로 막는 게 좋습니다.
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(bun run *)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git status)",
"Bash(* --version)",
"Bash(* --help *)"
],
"deny": ["Bash(rm -rf *)", "Bash(sudo *)"]
}
}
팀에서 공유하는 프로젝트 설정은 보안에 좀 더 신경 써야 합니다. 민감한 파일에 대한 Read 차단과 외부 네트워크 도구 차단을 함께 거는 게 효과적이에요.
{
"permissions": {
"allow": [
"Bash(npm run build)",
"Bash(npm run test *)",
"Bash(npm run lint)",
"Bash(npx prettier *)"
],
"deny": [
"Bash(rm -rf *)",
"Bash(sudo *)",
"Bash(curl *)",
"Bash(wget *)",
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Read(**/*.pem)",
"Read(**/*.key)"
]
}
}
이 파일을 Git에 커밋하면 팀원 전체에 동일한 규칙이 적용되죠.
클로드 코드 GitHub Actions 같은 CI/CD 환경에서는 사람의 승인 없이 실행되므로 필요한 권한만 정확히 열어둬야 합니다.
{
"permissions": {
"allow": [
"Bash(npm run build)",
"Bash(npm run test *)",
"Bash(npm run lint)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(git push *)"
],
"deny": ["Bash(rm -rf *)", "Bash(sudo *)"]
}
}
어떤 권한 모드와 조합할지는 상황에 따라 다릅니다.
개인 개발에는 acceptEdits, CI/CD에는 dontAsk이 잘 맞아요.
마치며
이 글에서는 allow/deny/ask 규칙과 도구별 패턴 문법, 설정 파일 계층, 샌드박스 연동을 다뤘습니다. 규칙이 “무엇을 허용/차단할까”를 정한다면 권한 모드는 “얼마나 자율적으로 작업하게 할까”를 정합니다. 두 설정을 함께 조합하면 팝업 피로를 줄이면서도 안전한 환경을 만들 수 있어요.
처음에는 사용자 설정에 자주 쓰는 명령어 허용 규칙만 넣어두는 것으로 충분합니다. 팀 프로젝트에서 일관된 규칙이 필요해지면 프로젝트 설정을 추가하고 보안이 중요한 환경에서는 샌드박스와 deny 규칙을 강화하면 돼요. 클로드 코드 Hooks로 커스텀 검증 로직까지 더하면 glob 패턴의 한계를 넘어선 정밀한 제어도 가능합니다. OS 레벨 격리까지 적용하고 싶다면 클로드 코드 샌드박스를 참고하세요.
더 자세한 내용은 Permissions 공식 문서를 참고하세요.
This work is licensed under
CC BY 4.0