
Claude Code의 PreToolUse 훅을 이용해 위험한 Bash 명령어를 자동 차단하는 구현 — permissionDecision과
요약
Claude Code의 PreToolUse 훅을 사용하여 위험한 Bash 명령어를 자동으로 차단하는 구현 방법을 설명합니다. 비대화형(headless) 환경에서의 동작 특성과 exit code 및 JSON 출력 방식의 차이점을 다룹니다.
핵심 포인트
- PreToolUse 훅을 통해 Bash 도구 호출 전 명령어를 검사하고 차단 가능
- exit code 2 방식과 JSON 출력 방식 중 하나로 구현 방식을 통일 권장
- Headless 실행 시 'ask' 결정은 자동으로 'deny' 처리됨에 유의
- 실행 차단은 PreToolUse, 사후 검증은 PostToolUse를 활용
Claude Code로 여러 프로젝트를 자동으로 구동시키다 보면,
rm -rf
이나 git push --force,
혹은 모르는 호스트에 대한 curl 같은 명령어를 에이전트가 실수로 실행하지 않을까 불안해진다. 설정 화면에서 매번 허가를 요청하게 하면 안전하지만, 비대화형(headless) 실행에서는 애초에 사람이 확인 프롬프트에 답할 수 없다.
이 글은 다음을 전제로 한다.
- Claude Code v2.x 계열 (hooks의
PreToolUse이벤트가 존재하는 버전) - Node.js 22.x / macOS 또는 Linux - 'Bash 도구를 호출하기 직전에, 명령어 문자열을 검사하여 위험하면 막고 싶다'는 니즈가 있는 사람들을 위한 내용.
settings.json의 permissions.allow/deny를 이용한 와일드카드 제어는 이미 알고 있다는 전제하에, 그것만으로는 부족한 경우(동적 판정 로직이 필요한 경우)에 초점을 맞춘다.
PreToolUse hook은 Bash 도구 호출의 바로 직전에 개입하여 명령어 문자열을 임의의 로직으로 검사할 수 있다. - 차단 방법은 두 가지가 있다: exit code 2(간편)와 JSON 출력(세밀한 제어). 이 둘을 혼용하면 한쪽이 무시될 수 있다.
matcher는 도구 이름(Bash 등)에만 매치된다. 명령어 문자열 자체의 패턴 매치는 hook 스크립트 측에서 직접 작성해야 한다. - headless (-p 옵션) 실행에서는 ask가 자동으로 deny 처리된다.
~/.claude/hooks/block-dangerous-bash.py 파일로 다음 내용을 넣는다. stdin으로부터 JSON이 전달되므로, tool_input.command를 추출하여 정규표현식으로 검사한다.
#!/usr/bin/env python3
import json
import re
...
실행 권한을 부여해 둔다.
chmod +x ~/.claude/hooks/block-dangerous-bash.py
~/.claude/settings.json (또는 프로젝트의 .claude/settings.json)에 다음을 추가한다.
{
골치 아픈 부분은 이 두 가지를 같은 스크립트 내에서 어정쩡하게 혼합했을 때의 동작입니다. exit code 2로 종료하면서 동시에 stdout에도 JSON을 작성했던 경우, JSON 쪽의 `permissionDecision`은 평가되지 않고 exit code 쪽의 판정이 우선되었습니다. **둘 중 하나의 방식에 통일하는 것**이 안전하며, 상세한 이유 문구를 반환하고 싶다면 JSON 방식을, 단순히 막기만 하면 된다면 exit code 2로 충분합니다.
대화 세션에서는 `permissionDecision: "ask"`를 반환하면 사람에게 확인 다이얼로그가 나타납니다. 하지만 `claude -p "..."`와 같은 헤드리스(headless) 실행에서는 확인할 상대가 없기 때문에, `ask`는 **자동으로 deny로 처리됩니다**. '회색 지대 명령어는 ask로 설정하여 인간의 판단을 구한다'라는 설계라면, 무인 실행 시 예상치 못하게 전부 차단되어 어려움을 겪을 수 있습니다. 무인 작업에서 사용할 hook은 `ask`를 사용하지 않고, `allow` 또는 `deny`의 이진(binary)으로 판정을 작성하는 설계로 하는 것이 사고가 없습니다. `PreToolUse`는 '도구 실행 전'에, `PostToolUse`는 '도구 실행 후'에 발동합니다. lint나 타입 체크를 자동으로 돌리고 싶다면 `PostToolUse`(Write/Edit 후에 발동)를, 실행 자체를 멈추고 싶다면 `PreToolUse`라는 구분이 있습니다. 같은 hook 메커니즘이라도 이벤트가 다르면 용도가 완전히 다르므로, 'hook을 설정했다'는 사실만으로 안심하지 말고, 어떤 이벤트에 등록했는지 매번 확인하는 습관을 들이는 것이 좋습니다.
-
`PreToolUse` hook에서는 Bash 명령어를 실행하기 전에 검사하여 위험한 패턴을 자동으로 차단할 수 있습니다. 블록 방식은 exit code 2와 JSON 출력을 두 가지 종류로 혼합하지 않고 통일해야 합니다.
- `matcher`는 도구 이름만 대상으로 하며, 명령어 문자열의 판정은 직접 작성해야 합니다. 헤드리스 실행에서는 `ask`가 자동으로 `deny`가 되므로, 무인 작업에서는 `allow`/`deny`의 이진 설계로 해야 합니다. 도입 후에는 `claude --debug`로 실제 판정 로그를 확인한 후에 운영에 적용하는 것이 안전합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기