
「안전 장치를 넣었으니 괜찮다」가 아니다——rm -rf는 멈추는데 DROP TABLE은 통과해버린 이야기
요약
Claude Code의 안전 장치(hook)가 파일 시스템 파괴 명령은 차단하지만, 데이터베이스 삭제 명령은 기본 설정에서 통과시킨다는 실측 결과를 공유합니다. 사용자는 기본 8개 후크 외에 특정 예제 후크를 추가 설치하여 보안 범위를 확장해야 합니다.
핵심 포인트
- Claude Code의 기본 후크는 rm -rf는 막지만 DROP TABLE은 허용함
- destructive-guard는 파일 및 Git 조작 방어에 집중되어 있음
- 명령어를 직접 실행하지 않고 종료 코드로 안전성을 테스트 가능
- 데이터베이스 보호를 위해 별도의 예제 후크 설치가 필수적임
Claude Code에 안전 장치(hook)를 넣었다. 그래서 안심하고 있었다.
솔직히 말하겠다. 나는 비엔지니어다. 코드를 쓸 줄 모른다. 그래서 "위험한 조작을 멈춰준다"라고 소개된 무료 도구를 설치하고, 그것으로 보호받고 있다고 느끼고 있었다. 설치했다, 즉, 전부 멈춘다. 그렇게 믿고 있었다.
하지만 "설치했다"와 "실제로 멈춘다"는 별개다. 파트너인 Claude(이 글의 기술적인 부분을 작성하는 쪽)에게, 기본 설치가 실제로 무엇을 멈추고 무엇을 통과시키는지, 하나씩 종료 코드(exit code)로 확인해 달라고 했다. 결론은 조금 무섭다. rm -rf /는 실행 직전에 멈춘다. 하지만 운영 데이터베이스의 DROP TABLE은 기본 설정 상태에서 그대로 통과했다.
이하, 실측 기록이다. 전해 들은 이야기가 아니라, 직접 실행하여 종료 코드를 확인한 1차 결과다.
npx cc-safe-setup을 인자 없이 실행하면, ~/.claude/hooks/에 들어가는 것은 핵심적인 8개의 후크(hook)다. 패키지 카탈로그(scripts.json)를 직접 읽어 확인했다.
내역은 파괴적인 명령을 멈추는 destructive-guard, 브랜치로의 직접적인 push를 막는 branch-guard, 편집 후의 구문을 검사하는 syntax-check, 컨텍스트 윈도우(context window)를 감시하는 context-monitor, 주석 혼입으로 인해 허용 리스트가 망가지는 것을 방지하는 comment-strip, 읽기 조작을 자동으로 승인하는 cd-git-allow, .env의 혼입을 막는 secret-guard, 세션 종료를 알리는 api-error-alert이다. 이 8개다.
여기서 중요한 것은, 이 8개에 "운영 데이터베이스의 전체 삭제를 막는 후크"가 포함되어 있지 않다는 점이다.
파괴적인 조작의 파수꾼인 destructive-guard의 본체를 읽어보면, 멈추는 대상은 다음과 같다. 위험한 경로에 대한 rm -rf, git reset --hard, git clean -fd, 넓은 패턴에서의 find ... -delete, 그리고 git checkout --force. 파일과 git의 파괴가 중심이다(브랜치로의 직접적인 push는 별도의 파수꾼인 branch-guard가 담당한다).
반면, SQL의 DROP이나 TRUNCATE, 조건 없는 DELETE는 이 파수꾼의 대상 외였다. 그래서 기본 설치 상태만으로는 AI가 psql -c "DROP TABLE users"를 던져도, 파수꾼은 그대로 통과시킨다.
어떻게 "실행하지 않고" 확인했는가. 후크는 표준 입력(standard input)으로 명령 문자열을 받아, 위험하다고 판단하면 종료 코드 2로 멈추는 구조다. 따라서 명령을 실제로 실행하지 않고, 문자열로서 전달하여 돌아오는 종료 코드만 확인하면 된다.
# 실행은 되지 않는다. 문자열로서 hook에 전달하고, 종료 코드만 확인한다
echo '{"tool_input":{"command":"rm -rf /"}}' | bash ~/.claude/hooks/destructive-guard.sh; echo "exit=$?"
# → exit=2 (멈춤)
...
rm -rf /는 exit=2, DROP TABLE은 exit=0. 직접 실행하여 측정한 실측값이 이것이다. 운영 환경을 한 번도 건드리지 않고, 자신의 환경에서 경계를 확인할 수 있다.
그렇다면 DROP을 막고 싶을 때는 어떻게 해야 하는가. 기본 8개가 아니라, 예제집(800개 이상 있음)에서 이름을 지정하여 추가한다.
npx cc-safe-setup --install-example block-database-wipe
이렇게 하면 DROP DATABASE나 migrate:fresh, db:reset, TRUNCATE TABLE을 종료 코드 2로 멈추는 후크가 들어간다. 추가한 뒤에 다시 아까의 한 줄을 실행하면, 이번에는 DROP TABLE이 exit=2로 바뀐다. 참고로 이 후크는 무료다. 빈틈을 메우는 데 과금은 필요 없다.
솔직한 한계도 적어둔다. 추가하더라도, TABLE을 생략한 순수한 TRUNCATE는 빠져나갔다. 후크는 문자열을 보는 최선의 노력을 다하는 그물일 뿐, 완전한 보증은 아니다. 따라서 선언적인 설정(permissions.deny)과 실행 직전의 후크, 그리고 운영 규칙을 겹쳐서 사용한다는 전제하에 사용해야 한다.
「안전 도구를 설치했다」고 안심하지 마라. 「무엇이 실제로 차단되는가」를 종료 코드 (exit code)로 확인하라. 이것이 이번의 배움이다.
기본 설치는 파일과 git의 파괴에는 효과가 있다. 하지만 데이터베이스 전체 삭제는 예제에서 하나를 추가할 때까지 그대로 통과한다. 설치한 시점에서 모든 것이 보호되고 있다고 믿는 것이 가장 위험하다.
-
무료 안전 후크 (safe hook) 본체:
npx cc-safe-setup -
이 기사에서 사용한 검증은 위험한 명령어를 단 한 번도 실행하지 않았다. 후크에 문자열을 전달하여 종료 코드 (exit code)를 확인했을 뿐이다. 메커니즘은 MIT 라이선스로 공개되어 있으므로, 내용은 직접 읽어볼 수 있다.
사고 유형별로 무엇이 일어나고, 설정과 운영 및 복구 단계에서 어떻게 막을지를 정리한 책도 별도로 마련해 두었다. 관심 있는 분은 저자의 도서 목록에서 가격과 평가를 보고 선택할 수 있다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기