Claude Code에 Bash 권한을 넓게 주고 쓰다 보면 rm -rf가 무서워집니다. 권한 확인 창을 매번 누르는 대신, 위험한 명령만 골라 아예 실행 전에 막는 방법이 있습니다. 훅(hooks)입니다.
근거: Claude Code 문서 Hooks reference, Automate workflows with hooks (2026년 11월 2일 확인). 아래 실행 결과는 Claude Code 2.1.316에서 확인했습니다.
훅이 하는 일
PreToolUse 훅은 Claude가 도구(Bash, Edit, Write 등)를 쓰기 직전에 내가 등록한 명령을 먼저 실행합니다. 훅은 실행하려는 도구 호출을 JSON으로 표준 입력에서 받습니다. Bash라면 tool_input.command에 실행할 명령이 들어 있습니다.
훅이 종료 코드 2로 끝나면 그 도구 호출은 막히고, Claude는 표준 에러(stderr)에 쓴 문장을 이유로 받습니다. 그걸 보고 다른 방법을 찾습니다. 종료 코드 0이면 평소처럼 진행합니다.
1. 훅 스크립트
.claude/hooks/block-rm.sh에 저장합니다. jq가 필요합니다(macOS는 brew install jq).
#!/bin/bash
CMD=$(jq -r '.tool_input.command // empty')
if echo "$CMD" | grep -Eq '(^|[;&|[:space:]])rm[[:space:]].*(-[a-zA-Z]*[rR]|--recursive)'; then
echo "막음: 재귀 삭제(rm -r)는 직접 실행하세요: $CMD" >&2
exit 2
fi
exit 0
chmod +x .claude/hooks/block-rm.sh
2. 등록
프로젝트의 .claude/settings.json에 넣습니다. 모든 프로젝트에 걸고 싶다면 ~/.claude/settings.json에 넣습니다.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-rm.sh"
}
]
}
]
}
}
시켜 봤다
빈 폴더에 build/app.js를 만들고, 훅을 건 상태에서 Claude Code에 rm -rf build를 그대로 실행하라고 시켰습니다.
$ claude -p "Run exactly this shell command with the Bash tool: rm -rf build"
프로젝트의 PreToolUse 훅(block-rm-rf.sh)이 rm -rf build 실행을 막았고, 명령은 실행되지 않았습니다.
$ ls build
app.js
명령은 실행되지 않았고 파일은 그대로 남았습니다.
함정: 글자 비교는 빠져나간다
문서의 예시처럼 *"rm -rf"* 같은 글자 비교로만 막으면, 옵션 순서만 바꿔도 통과합니다.
| 명령 | *"rm -rf"* 비교 | 위 스크립트(정규식) |
|---|---|---|
rm -rf build | 막힘 | 막힘 |
rm -fr build | 통과 | 막힘 |
rm -r -f build | 통과 | 막힘 |
rm --recursive build | 통과 | 막힘 |
cd a && rm -rf b | 막힘 | 막힘 |
rm file.txt | 통과 | 통과 |
위 스크립트도 완벽하지는 않습니다. 같은 줄에 rm과 -r 옵션을 가진 다른 명령이 함께 있으면(예: rm a.txt && ls -r) 함께 막힙니다. 반대로 find . -delete나 파이썬 스크립트 안의 삭제는 이 훅이 보지 못합니다. 훅은 실수를 막는 장치입니다. 작정하고 돌아가는 명령까지 막지는 못합니다. 중요한 작업 전에는 git 커밋을 함께 해 두세요.
알아둘 것
- 같은 이벤트에 훅이 여러 개 걸려 있으면 모두 실행되고, 하나라도 거부(deny)하면 막힙니다.
- 종료 코드 2의 의미는 이벤트마다 다릅니다.
PreToolUse에서는 막지만,PostToolUse는 도구가 이미 실행된 뒤라 막지 못하고 메시지만 전달합니다. - 훅 스크립트는 실행 권한이 있어야 합니다(
chmod +x).
오늘 할 일
자주 쓰는 프로젝트에 .claude/hooks/block-rm.sh 하나와 설정 몇 줄을 넣어 두세요. 그리고 rm -fr 같은 변형으로 한 번 시험해서 막히는지 확인하세요.