본문 바로가기
AI 툴 문제 해결

Claude Code 위험 명령어 PreToolUse 훅으로 차단하기

by 오소리 이랩 2026. 7. 25.
Claude Code 활용법

Claude Code가 도구를 실행하기 직전, 위험한 명령을 자동으로 걸러주는 PreToolUse 훅의 동작 원리부터 설정 방법, 실전 활용 팁까지 단계별로 정리합니다.

📌 3줄 요약

  • PreToolUse 훅은 Claude Code가 도구를 실행하기 직전에 사용자 스크립트를 먼저 실행하여 위험한 명령을 자동 차단하는 기능이다.
  • settings.json에 matcher와 command를 등록하면 특정 도구에만 훅을 적용할 수 있다.
  • 차단 스크립트를 작성하면 rm -rf / 같은 위험 명령과 저장소 밖 파일 쓰기를 자동으로 막을 수 있다.

PreToolUse 훅이 필요한 상황과 동작 원리

Claude Code는 사용자의 요청을 수행하기 위해 파일 편집, 터미널 명령 실행, 파일 생성 등 다양한 도구를 직접 호출합니다.

문제는 이 과정에서 rm -rf /처럼 위험한 명령이나, 프로젝트 폴더 바깥에 파일을 쓰는 실수가 발생할 수 있다는 점입니다.

⚠️ 특히 자동 허용 모드를 켜두면 사용자가 미처 확인하지 못한 채 위험한 명령이 바로 실행될 수 있어서 더 주의가 필요합니다.

PreToolUse 훅(hook)은 Claude Code가 도구를 실행하기 직전에 사용자가 지정한 스크립트를 먼저 실행하는 기능입니다. 이 스크립트가 "차단"을 반환하면 해당 도구 호출이 취소됩니다. 반대로 스크립트가 정상 종료를 반환하면 도구가 그대로 실행되기 때문에, 허용할 명령과 차단할 명령을 스크립트 안에서 자유롭게 구분할 수 있습니다.

🔍 쉽게 비유하면 공항 보안 검색대와 비슷합니다. 승객(도구 호출)이 탑승 게이트(실행)에 도달하기 전에 검색대(훅 스크립트)를 통과해야 하는 구조입니다. 검색대에서 위험물이 감지되면 탑승이 거부되듯, 훅 스크립트가 위험 패턴을 감지하면 도구 호출이 즉시 취소됩니다.

💬 제가 직접 써보니, 훅 없이 Claude Code를 쓸 때는 매번 도구 호출 알림을 눈으로 확인하고 수동으로 허용/거부를 판단해야 했습니다. 훅을 설정하고 나면 위험한 패턴은 자동으로 걸러지기 때문에 안심하고 자동 허용 모드를 활용할 수 있습니다. 사람이 일일이 판단하는 것보다 스크립트가 기계적으로 걸러주는 편이 실수도 적고 작업 흐름도 끊기지 않아서 훨씬 편리합니다.

settings.json에 PreToolUse 훅 등록하는 법

훅 설정은 .claude/settings.json 파일에 작성합니다. 이 파일이 없으면 프로젝트 루트에 .claude 폴더를 만들고 settings.json을 새로 생성하면 됩니다. 이미 .claude 폴더가 존재하는 경우에는 기존 settings.jsonhooks 키만 추가하면 됩니다.

기본 구조는 다음과 같습니다.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python .claude/hooks/block_dangerous_cmd.py"
          }
        ]
      }
    ]
  }
}

matcher 필드는 어떤 도구에 훅을 적용할지 지정합니다. Bash로 설정하면 터미널 명령 실행 도구에만 훅이 동작합니다. 만약 모든 도구에 훅을 적용하고 싶다면 matcher를 생략하거나 ".*" 같은 정규식 패턴을 사용할 수도 있습니다.

command 필드에는 실행할 스크립트 경로를 넣습니다. 이 스크립트는 표준 입력(stdin)으로 도구 호출 정보를 JSON 형태로 전달받습니다. JSON에는 tool_nametool_input 필드가 포함되어 있어서 어떤 도구가 어떤 인자로 호출되었는지 스크립트 안에서 확인할 수 있습니다.

 

🔍 훅 스크립트가 종료 코드 2를 반환하면 도구 호출이 차단됩니다. 종료 코드 0을 반환하면 정상적으로 도구가 실행됩니다. 차단 시 사용자에게 보여줄 메시지는 stdout에 JSON 형식으로 출력합니다. 형식은 {"decision": "block", "reason": "차단 사유"} 입니다.

위험 명령과 저장소 밖 쓰기를 차단하는 스크립트

이제 실제 차단 로직을 담은 파이썬 스크립트를 작성합니다. .claude/hooks/block_dangerous_cmd.py 파일을 만들어 봅니다.

import sys
import json
import os

def main():
    input_data = json.loads(sys.stdin.read())
    tool_name = input_data.get("tool_name", "")
    tool_input = input_data.get("tool_input", {})

    # Bash 명령 차단 목록
    if tool_name == "Bash":
        command = tool_input.get("command", "")
        dangerous = ["rm -rf /", "rm -rf ~", "mkfs", "dd if=",
                      "> /dev/sda", "chmod -R 777 /"]
        for pattern in dangerous:
            if pattern in command:
                result = {"decision": "block",
                          "reason": f"위험 명령 감지: {pattern}"}
                print(json.dumps(result))
                sys.exit(2)

    # Write/Edit 도구의 저장소 밖 경로 차단
    if tool_name in ("Write", "Edit"):
        file_path = tool_input.get("file_path", "")
        repo_root = os.getcwd()
        abs_path = os.path.abspath(file_path)
        if not abs_path.startswith(repo_root):
            result = {"decision": "block",
                      "reason": f"저장소 밖 쓰기 차단: {abs_path}"}
            print(json.dumps(result))
            sys.exit(2)

    sys.exit(0)

if __name__ == "__main__":
    main()

dangerous 리스트에 차단할 명령어 패턴을 추가하면 됩니다. 예를 들어 "sudo shutdown" 같은 패턴을 리스트에 넣으면 시스템 종료 명령도 차단할 수 있습니다.

저장소 밖 쓰기 차단은 os.path.abspath()로 절대 경로를 비교하는 방식으로 동작합니다. 상대 경로로 ../../etc/passwd 같이 상위 디렉토리를 타고 올라가는 경우도 절대 경로로 변환한 뒤 비교하기 때문에 우회가 어렵습니다.

 

Claude Code 위험 명령어 PreToolUse 훅으로 차단하기

Write와 Edit 도구도 함께 차단하려면 settings.jsonmatcher를 추가해야 합니다. 다음과 같이 배열에 항목을 하나 더 넣으면 됩니다.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{"type": "command",
                    "command": "python .claude/hooks/block_dangerous_cmd.py"}]
      },
      {
        "matcher": "Write|Edit",
        "hooks": [{"type": "command",
                    "command": "python .claude/hooks/block_dangerous_cmd.py"}]
      }
    ]
  }
}

matcherWrite|Edit처럼 파이프(|)로 여러 도구를 지정할 수 있습니다. 하나의 스크립트로 여러 도구를 동시에 감시하는 구조입니다.

💬 제가 직접 써보니, 차단 패턴을 너무 넓게 잡으면 정상적인 rm 명령까지 막히는 문제가 있었습니다. 예를 들어 단순히 "rm"만 패턴으로 넣으면 rm temp.txt 같은 안전한 파일 삭제까지 전부 차단됩니다. rm -rf /처럼 구체적인 패턴으로 좁히되, 프로젝트 내부 파일 삭제는 허용하는 쪽이 실용적이었습니다.

훅 동작 확인과 실전 활용 팁

설정을 마쳤으면 실제로 차단이 되는지 테스트해야 합니다. Claude Code에게 "rm -rf / 실행해줘"라고 요청하면 훅이 동작하여 차단 메시지가 표시됩니다. 마찬가지로 프로젝트 폴더 바깥 경로에 파일을 써달라고 요청하면 Write 도구가 차단되는 것도 확인할 수 있습니다.

 

Claude Code 위험 명령어 PreToolUse 훅으로 차단하기
Claude Code 위험 명령어 PreToolUse 훅으로 차단하기

차단되면 Claude Code 화면에 훅이 반환한 reason 메시지가 나타납니다. Claude Code는 차단 사유를 읽고 대안을 스스로 제시하기 때문에 작업이 완전히 멈추지는 않습니다. 정상 동작을 확인한 뒤 자동 허용 모드와 함께 쓰면 효과가 극대화됩니다.

실전에서 유용한 팁 몇 가지를 정리합니다.

💡 차단 패턴은 정규식 대신 단순 문자열 매칭으로 시작하는 것을 권장합니다. 정규식은 강력하지만 예상치 못한 오탐이 발생하기 쉽습니다. 단순 문자열 매칭으로 충분한 경우가 대부분이므로, 필요할 때만 정규식으로 전환하는 순서가 안전합니다.

💡 훅 스크립트에서 stderr로 로그를 남기면 디버깅에 도움이 됩니다. print("검사 중: " + command, file=sys.stderr) 한 줄이면 충분합니다. 로그를 남겨두면 어떤 명령이 훅을 통과했고 어떤 명령이 차단됐는지 나중에 추적할 수 있어서 규칙을 개선할 때 유용합니다.

💡 팀 프로젝트에서는 .claude/hooks/ 폴더를 Git에 포함시켜 공유하면 됩니다. 모든 팀원이 동일한 안전 규칙을 적용받게 됩니다.

🔍 settings.json은 프로젝트별(.claude/settings.json)과 사용자별(~/.claude/settings.json) 두 곳에 설정할 수 있습니다. 프로젝트별 설정이 우선 적용되므로, 공통 규칙은 프로젝트 단위로 관리하는 편이 깔끔합니다.

💬 제가 직접 써보니, 훅 스크립트에 문법 오류가 있으면 Claude Code가 도구 자체를 실행하지 못하고 멈추는 현상이 있었습니다. 훅 스크립트를 수정한 뒤에는 반드시 python .claude/hooks/block_dangerous_cmd.py 명령으로 단독 실행하여 오류가 없는지 먼저 확인하는 습관이 중요합니다. 스크립트 단독 실행 시 stdin에 테스트용 JSON을 파이프로 넘기면 차단 로직까지 함께 검증할 수 있어서 더 확실합니다.

✍️ 마치며

PreToolUse 훅은 Claude Code의 강력한 자동화 능력을 안전하게 활용할 수 있게 해주는 핵심 장치입니다. settings.json에 몇 줄만 추가하면 위험 명령 차단과 저장소 밖 쓰기 방지를 자동화할 수 있습니다. 차단 패턴은 단순하게 시작해서 필요에 따라 점진적으로 확장하고, 팀 단위로 공유하면 모두가 같은 안전망 위에서 작업할 수 있습니다. 자동 허용 모드와 함께 사용하면 안전성과 생산성을 동시에 확보할 수 있으니, 아직 설정하지 않았다면 오늘 바로 시작해 보세요.

#ClaudeCode #PreToolUse #훅설정 #위험명령차단 #AI코딩안전 #settingsjson