Claude Code 권한 설정: allow·deny 규칙 문법과 자주 새는 패턴
Windows 11에서 deny에 Read(./.env)를 넣어 두고 세션을 돌려 봤습니다. Claude가 Get-Content .env를 실행하자 제대로 막히긴 했어요. 그런데 Claude가 받은 메시지는 이랬습니다.
get-content targeting '<프로젝트 경로>\.env' was blocked. For security, Claude Code may only access files in the allowed working directories for this session: '<프로젝트 경로>', '<프로젝트 경로>'.
.env는 작업 폴더 바로 안에 있었고, deny 규칙을 빼면 그대로 읽혔습니다. 막은 건 분명히 제 deny 규칙인데, 메시지만 보면 “작업 폴더 밖이라서” 막힌 것처럼 읽히더라고요.
권한 규칙은 이렇게 걸리는 모습과 이유가 어긋나 보일 때가 있어서, 규칙이 어떤 순서로 평가되고 어디서 의도보다 넓게 열리는지를 알고 쓰는 게 중요합니다. .env를 이렇게까지 막아 두는 이유, 그러니까 한 번 읽힌 값이 서버와 로컬 기록에 어디까지 남는지는 Claude Code 학습·데이터 보존 글에 따로 정리했어요.
이 글은 2026년 9월 9일 공식 문서(권한, 설정, 권한 모드) 기준입니다. 명령줄 플래그는 Claude Code 2.1.150에서, Windows에서 규칙이 걸리는 모습은 2026년 9월 30일 Windows 11 · PowerShell 5.1 · Claude Code 2.1.283 테스트 환경에서 직접 확인했고, 셸 명령이 어느 도구로 도는지는 10월 13일 2.1.296에서 다시 확인했습니다.
설치가 아직이라면 Windows 설치 글을, 지시 파일부터 정리하려면 CLAUDE.md 작성법을 보세요.
확인한 버전·환경
- Claude Code 2.1.296 · Windows 11 · Windows PowerShell 5.1 · 확인일 2026-10-13
구체적인 규칙이 이기는 게 아니다
권한은 settings.json의 permissions.allow / ask / deny 세 목록으로 정합니다. 세션 안에서 /permissions로 편집해도 되고요.
{
"permissions": {
"allow": ["Bash(npm run *)", "Bash(git commit *)"],
"deny": ["Bash(git push *)"]
}
}
그럼 Bash(aws *)를 deny에 넣고 Bash(aws s3 ls)를 allow에 넣으면 aws s3 ls는 실행될까요? 안 됩니다. 규칙은 deny → ask → allow 순서로 보고 처음 맞는 규칙이 결과를 정하며, 더 구체적인 규칙이라고 순서가 바뀌지 않거든요. deny에는 예외를 달 수 없습니다.
allow에 넣었는데 또 묻는다면 답은 대개 이 순서에 있습니다. ask와 allow 사이도 같아서, 더 구체적인 allow가 있어도 맞는 ask가 있으면 물어봐요. 같은 증상이면 먼저 맞는 deny나 ask가 있는지부터 보세요.
deny에 도구 이름만 적는 것과 패턴을 적는 것은 효과가 다릅니다.
| 형태 | 효과 |
|---|---|
"Bash", "Bash(*)" |
도구를 Claude의 컨텍스트에서 아예 뺌 |
"Bash(rm *)" |
도구는 두고 맞는 호출만 막음 |
괄호 안에 쓰는 것
규칙은 도구(대상) 형식입니다.
| 규칙 | 뜻 |
|---|---|
Bash(npm run build) |
정확히 npm run build |
Bash(npm run *) |
npm run으로 시작하는 명령 |
Read(./.env) |
현재 폴더의 .env 읽기 |
WebFetch(domain:github.com) |
github.com으로의 요청 |
규칙을 적었는데 무시되는 것 같다면 보통 아래 경우 중 하나입니다. 모두 시작할 때 경고가 뜨고 claude doctor에도 나와요.
Write·Glob에 경로 규칙을 썼다. 파일 규칙은Read와Edit으로만 검사됩니다.Write,NotebookEdit,Glob, 예전MultiEdit의 경로 규칙은 받아들여지지만 검사에 쓰이지 않습니다(v2.1.210 이상).Write(docs/**)대신Edit(docs/**),Glob(docs/**)대신Read(docs/**)를 쓰세요.Bash(command:rm *)처럼필드:값으로 썼다. Bash의command, 파일 도구의file_path, Grep·Glob의path, WebFetch의url은 이렇게 맞출 수 없습니다. 복합 명령으로 우회할 수 있어서 무시돼요.Bash(rm *)로 씁니다.mcp__규칙에 괄호를 넣었다. MCP 도구 규칙에는 괄호를 쓸 수 없습니다. allow의 글롭은mcp__퍼펫티어__*처럼 서버 이름까지 그대로 적어야 하고,"*"나"mcp__*"같은 열린 글롭은 allow에서 건너뜁니다(deny에서는 동작).
경로는 앞에 붙은 표시에 따라 기준이 다릅니다.
| 표기 | 기준 | 예 |
|---|---|---|
//path |
파일 시스템 루트 | Read(//Users/alice/secrets/**) |
~/path |
홈 폴더 | Read(~/Documents/*.pdf) |
/path |
설정 파일 위치 | 프로젝트 설정의 Edit(/src/**/*.ts) |
path, ./path |
현재 폴더 | Read(*.env) |
제가 보기엔 세 번째 줄이 제일 위험한 함정입니다. 사용자 설정(~/.claude/settings.json)에 Read(/secrets/**)를 쓰면 프로젝트의 secrets가 아니라 ~/.claude/secrets/**를 막거든요. 모든 프로젝트에 걸 규칙은 //나 ~/로 쓰세요.
심볼릭 링크는 링크 경로와 가리키는 경로를 모두 보는데, allow는 둘 중 하나만 맞으면 묻는 쪽으로 물러서고 deny는 하나라도 맞으면 막습니다.
Read(./.env)같은 deny는 Claude의 파일 도구,cat·head·tail·sed같은 알아보는 파일 명령,> file·< file리디렉션까지만 막습니다. 파이썬이나 노드 스크립트가 안에서 여는 파일은 막지 못하니, 프로세스 단위로 막으려면 샌드박스를 켜세요.
생각보다 넓게 열리는 패턴
allow가 의도보다 넓어지는 자리는 앞쪽 와일드카드, &&·|로 이은 명령, 래퍼와 실행기입니다. 하나씩 보겠습니다.
1. 와일드카드를 앞에 두면 프로그램 전체가 열린다
첫 * 앞의 글자는 그대로 맞춰 보고, 그 앞 단어들이 범위를 정합니다. 그래서 별표 앞에 무엇이 오느냐가 전부예요.
| 규칙 | 허용됨 | 허용 안 됨 |
|---|---|---|
Bash(npm run *) |
npm run build, npm run |
npm install |
Bash(git log * main) |
git log --oneline main |
git log main, git push origin main |
Bash(git * main) |
git push origin main, git -c core.fsmonitor=<스크립트> diff main |
git log |
Bash(* --version) |
node --version, bash -c 'echo hi' --version |
node -v |
git -c는 git이 임의의 프로그램을 실행하게 만드는 옵션이라, Bash(git * main)은 사실상 임의 실행을 엽니다. Bash(* --version)도 * 자리에 아무 프로그램이나 올 수 있고요. 서브커맨드 앞에 *가 있는 allow 규칙에는 시작할 때 경고가 뜨니, 보이면 그냥 넘기지 말고 다시 쓰세요.
2. 공백 한 칸이 범위를 바꾼다
Bash(ls *)는 ls -la와 ls에 맞고, Bash(ls*)는 ls -la와 lsof에 맞습니다. 끝 * 앞의 공백도 규칙의 일부라서, 공백이 있으면 ls 뒤에 공백이 와야 해요.
끝 *가 유일한 와일드카드면 인자 없는 명령(ls, git log)도 맞지만, Bash(* --help *)처럼 둘이면 이 규칙이 적용되지 않아 npm --help는 안 맞습니다. Bash(ls:*)는 Bash(ls *)와 같고, 단 :*는 패턴 끝에서만 그렇습니다(Bash(git:* push)의 콜론은 그냥 글자).
3. 이은 명령은 allow와 deny가 반대로 걸린다
Claude Code는 &&, ||, ;, |, |&, &, 줄바꿈으로 명령을 나눠 봅니다.
- allow는 나뉜 명령이 모두 맞아야 합니다.
Bash(safe-cmd *)가 있어도safe-cmd && other-cmd는 허용되지 않아요. - deny·ask는 하나라도 맞으면 적용되고, 서브셸·명령 치환·
for본문 안까지 봅니다.Bash(git clean *)를 ask에 두면cd /tmp && git clean -f나echo "$(git clean -f)"도 묻습니다.
npm test &&처럼 뒤가 비면 해석할 수 없는 명령으로 보고 나누지 않아서, Bash(npm *) 같은 allow로도 승인되지 않습니다.
4. 래퍼는 벗겨지고, 실행기는 안 벗겨진다
규칙을 맞추기 전에 timeout, time, nice, nohup, stdbuf, 셸 내장 command·builtin, zsh의 noglob, 플래그 없는 xargs는 벗겨 냅니다. 그래서 Bash(npm test *)는 timeout 30 npm test에도 맞아요.
알려진 안전한 환경 변수 할당도 벗겨져 NODE_ENV=test npm test가 맞고, deny·ask는 어떤 할당이든 건너뛰고 보므로 FOO=bar rm -rf tmp/도 Bash(rm *)에 걸립니다.
조심할 건 목록에 없는 실행기입니다. direnv exec, devbox run, mise exec, npx, docker exec는 벗겨지지 않는데 인자를 명령으로 실행하거든요.
그래서 Bash(devbox run *)는 devbox run rm -rf .까지 허용합니다. 실행기를 쓴다면 Bash(devbox run npm test)처럼 안쪽 명령까지 적은 규칙을 하나씩 만드는 편이 안전합니다.
Windows에서 직접 걸어 본 규칙
Windows에서는 셸 명령이 어느 도구로 도는지가 2.1.283과 2.1.296 두 실행에서 갈렸습니다. 2.1.283에서는 PowerShell 도구로 돌아 Bash(...) 규칙이 맞지 않았는데, 10월 13일 2.1.296에서는 같은 명령이 Bash 도구로 돌아 반대로 PowerShell(...) 규칙이 맞지 않았어요.
그래서 Windows에서는 Bash(git commit *)와 PowerShell(git commit *)처럼 두 도구 규칙을 함께 적는 편이 안전합니다.
두 버전에서 같은 git commit을 각 규칙으로 허용해 본 결과는 헤드리스 모드 글의 Windows 절에 있습니다.
Windows 11 · 2.1.283에서 직접 실행한 세션에서는 규칙이 이렇게 걸렸습니다.
| 규칙 | Claude가 실행한 명령 | 결과 |
|---|---|---|
deny PowerShell(Remove-Item *) |
del old-notes.txt |
거부(규칙 없으면 삭제됨) |
allow PowerShell(git commit *)만 |
git commit …; New-Item … |
줄 전체 거부 |
deny Read(./.env) |
Get-Content .env |
거부(규칙 없으면 출력됨) |
별칭도 막힙니다. 흔한 별칭은 원래 이름으로 바꾼 뒤 규칙과 맞추기 때문에, del이 Remove-Item 규칙에 그대로 걸렸어요. 별칭마다 규칙을 따로 쓸 필요는 없습니다.
이은 명령은 전부 허용돼야 합니다. PowerShell에서는 |와 ;(PowerShell 7 이상은 &&·||도)로 나눕니다. 실제 명령은 git commit --allow-empty -m probe; New-Item -ItemType File extra.txt였는데, 뒤의 New-Item 때문에 앞의 커밋도 실행되지 않았습니다.
Read(./.env)는 셸 읽기도 막습니다. Read 도구뿐 아니라 Get-Content .env도 막혔죠.
차단 메시지가 엉뚱한 원인을 가리킬 때
도입에서 본 그 메시지 얘기입니다. 끝의 두 경로는 같은 폴더를 역슬래시와 슬래시로 적은 것이고, 실제로 막은 건 Read(./.env) 규칙이었어요. 그러니 이 메시지가 나와도 --add-dir부터 고치지 말고, 그 파일에 걸린 Read·Edit deny가 있는지 먼저 보세요.
검사를 통째로 끄기 전에
설정 파일을 고치지 않고 한 번만 적용하려면 플래그를 씁니다. Claude Code 2.1.150의 claude --help에서 확인한 것들입니다.
--allowedTools/--disallowedTools: 허용·거부할 도구를 쉼표나 공백으로 나열합니다. 예:"Bash(git *) Edit"--add-dir <폴더>: 도구가 접근할 폴더를 더합니다.--dangerously-skip-permissions: 모든 권한 검사를 건너뜁니다. 도움말 스스로 인터넷 접근이 없는 샌드박스에서만 쓰라고 권합니다.--allow-dangerously-skip-permissions: 위 동작을 기본으로 켜지는 않고 고를 수 있게만 합니다. 같은 권고가 붙어 있습니다.
프롬프트가 귀찮으면 검사를 아예 꺼 버리고 싶어지죠. 보안 관점의 공개 글은 이 플래그가 자격 증명이 있는 폴더에서 특히 위험하다고 지적합니다.
Claude Code Security는 2026년 7월 Locking Down Claude Code with settings.json에서 ~/.ssh, ~/.aws, 클라우드 토큰, 값이 채워진 .env가 닿는 곳에서는 쓰지 말라고 권합니다.
프롬프트가 없으면 잘못 읽은 지시나 오염된 문서 한 건이 파일 삭제나 비밀 유출로 이어질 수 있어서입니다.
저도 같은 쪽을 권합니다. 넓은 범주 대신 좁은 명령 패턴을 allow에 넣고, 자격 증명과 파괴적 작업은 deny에 명시하세요. 공식 문서도 curl·wget은 deny로 막고 필요한 도메인만 WebFetch(domain:...)로 열라고 권합니다.
2026년 3월 이후에는 auto 모드라는 중간 단계도 생겼습니다. 분류기 모델이 대부분의 동작을 대신 검토하고 위험해 보이는 것만 막아서, 프롬프트를 줄이려고 검사를 통째로 끌 이유가 줄었어요. 모드 비교는 권한 모드 고르기: 수동·plan·auto·dontAsk는 언제 쓰나에 있습니다.
아래는 이 글을 위해 새로 쓴 시작용 예시입니다. 정적 사이트를 빌드하는 Node 프로젝트의 .claude/settings.json을 가정했고, Windows에서는 셸 명령 규칙을 앞 절처럼 Bash(...)와 PowerShell(...)로 둘 다 적어 두세요.
{
"permissions": {
"allow": ["Bash(npm ci)", "Bash(npm run build)", "Bash(npm run test *)",
"Bash(git status *)", "Bash(git diff *)", "Bash(git log *)"],
"ask": ["Bash(git commit *)", "Bash(git push *)"],
"deny": ["Read(./.env)", "Read(./.env.*)", "Read(~/.ssh/**)", "Read(~/.aws/**)",
"Bash(curl *)", "Bash(wget *)", "Bash(rm *)"]
}
}
allow에는 되돌릴 수 있는 작업만 두고 별표는 모두 서브커맨드 뒤에 뒀습니다. 바깥에 흔적이 남는 commit·push는 ask로 한 번 멈추고, 비밀 파일·네트워크 도구·삭제는 deny로 잠급니다. 이 파일을 커밋하면 팀이 같이 쓰고, 개인 예외는 .claude/settings.local.json에 두면 됩니다(설정 파일 우선순위).
마치며
권한 규칙에서 제일 많이 틀리는 건 문법보다 순서와 범위입니다. 구체적인 allow가 deny를 이길 거라고 기대하거나, 별표 하나를 앞에 둬서 프로그램 전체를 열어 버리는 식이죠. Windows에서 직접 걸어 보니 셸 명령 규칙은 Bash(...)와 PowerShell(...)를 둘 다 적어 둬야 한다는 것, 그리고 막힌 이유가 메시지와 다를 수 있다는 것까지 알아 둬야 했습니다.
지금 쓰는 settings.json에서 *가 서브커맨드 앞에 있는 allow 규칙이 있는지 한 번 훑어보세요. 매번 반드시 실행돼야 하는 일(편집 후 포맷, 커밋 전 테스트)은 권한이 아니라 훅으로 거는 방법으로 이어집니다.
참고한 공식 자료
모두 2026년 9월 9일에 확인했습니다.
- Configure permissions — 규칙 문법, 평가 순서, 와일드카드·명령 연결·래퍼 규칙, 경로 기준, PowerShell 규칙
- Settings files and precedence — 설정 파일 위치와 우선순위
- Choose a permission mode — 권한 모드와 auto 모드
인용한 공개 사례
- Claude Code Security, 2026-07, Locking Down Claude Code with settings.json — 자격 증명 폴더에서의 위험과 좁은 allow·명시적 deny 권고
변경 이력
- 2026-10-14 — 예시와 마무리가 Windows에서는 PowerShell(...)로 적으라고 하던 것을, 두 실행 결과에 맞게 Bash(...)와 PowerShell(...)를 함께 적으라는 권고로 고쳤습니다.
- 2026-10-13 — Windows에서 셸 명령이 PowerShell 도구로 돈다는 설명을 고쳤습니다. 2.1.283에서는 PowerShell 도구였지만 2.1.296에서는 같은 명령이 Bash 도구로 돌아, 두 도구 규칙을 함께 적으라고 안내합니다.
- 2026-09-30 — Windows 11에서 권한 규칙을 실제 세션으로 확인한 절을 더했습니다. Windows에서는 명령이 PowerShell 도구로 실행돼 PowerShell(...) 규칙이 필요하다는 점, 별칭·이어 붙인 명령·.env 차단이 어떻게 걸렸는지, 차단 메시지가 원인과 다른 곳을 가리킨 점을 다룹니다.