내 자체 후크와 Claude Code의 권한 검사 모두에 존재했던 동일한 취약점: `2>/dev/null`이 둘 다 통과하는 방법
요약
본 글은 Claude Code 환경에서 개발자가 구현한 자체 보안 후크와 공식 권한 검사 시스템 모두에 존재하는 동일한 취약점을 분석합니다. 핵심적으로 `2>/dev/null` 리다이렉션 기호가 텍스트 기반의 위험 감지 로직을 우회하는 방법을 설명하며, 단일 방어 메커니즘에 의존하지 말고 다층적인 보안 전략을 구축할 것을 강조합니다.
핵심 포인트
- `2>/dev/null`은 셸과 텍스트 스캐닝 그물망 간의 차이를 이용해 권한 검사를 우회한다.
- 단일 후크나 공식 권한 시스템에 의존하지 말고 다층적인 방어 메커니즘을 구축해야 한다.
- 위험 작업 전에는 항상 목록화(find) 및 드라이런(dry run)을 습관화하라.
- 삭제 대상을 변수 대신 상대 경로로 명시적으로 지정하여 위험을 줄여라.
저는 Claude Code를 거의 24시간 내내, 대부분 무인 상태로 실행합니다. 이 코드는 쉘 접근(shell access)을 가지고 있기 때문에 제가 가장 두려워하는 것은 실수로 인한 광범위한 삭제입니다. 저는 위험한 삭제를 두 가지 방식으로 막습니다. 바로 실행 직전에 이를 차단하는 저만의 후크와 Claude Code 자체의 권한 시스템입니다. 저는 이 두 개의 그물망이 있다고 생각했습니다.
그런데 저는 하나의 그물망에 구멍을 발견했습니다. 그리고 며칠 후, 저는 다른 그물망 — 즉 Claude Code의 공식 권한 검사 — 역시 정확히 같은 모양의 구멍을 가지고 있다는 것을 알게 되었습니다. 이 게시글은 제가 자체 종료 코드(exit code)로 측정한 결과를, 공식 도구에 동일한 간격이 존재했다는 사실과 나란히 기록한 것입니다.
내 자체 후크가 2>/dev/null을 통과하게 만든 방법
저는 무료 후크 모음인 cc-safe-setup을 공개했는데, 이 핵심에는 위험한 삭제를 차단하는 후크가 있습니다. 저는 표준 입력(standard input)의 모든 명령어에 이를 넣어보고, 그것이 멈추는지(종료 코드 2) 아니면 통과시키는지(0) 측정했습니다. 어떤 위험한 명령어도 실행되지 않았습니다. 저는 오늘 실제로 사용할 수 있는 npx cc-safe-setup 버전(npm에서 게시된 29.8.0, 2026년 7월 기준)을 사용했습니다. 후크는 업데이트되므로, 제가 확인했을 당시의 동작으로 간주해 주십시오.
| 명령어 | 종료 코드 | 결과 |
|---|---|---|
rm -rf ~ | 2 | 차단됨 |
| ... |
왜 그것이 빠져나갈까요? 텍스트 일치로 위험을 판단하는 그물망은 문자 하나하나를 검토하며 '삭제 대상이 어디서 끝나는지?'를 결정하려고 합니다. 2>/dev/null은 셸(shell)에게는 별개의 명령어(표준 에러(stderr)를 아무데도 리다이렉션)이지만, 텍스트 스캐닝 그물망은 그곳에서 자리를 잃습니다. 셸이 실제로 하는 일과 그물망이 텍스트가 무엇이라고 생각하는 것 사이에 차이가 생깁니다. 리디렉션 기호는 바로 그 간극에 쐐기를 박는 역할을 합니다.
공식 권한 검사에서도 같은 사각지대가 있었습니다
만약 이것이 오직 저의 후크(hook)에 관한 것이었다면,
우선 Claude Code를 2.1.214 버전 이상으로 업그레이드하세요. 위에서 언급된 권한 검사 우회는 해당 릴리스에서 막혔습니다. 이것이 가장 저렴하고, 가장 확실하며, 무료인 단일 조치입니다.
하지만 여기서 멈추지 마세요. 하나의 릴리스에서 다섯 개의 구멍이 막혔다는 사실 자체가 표면적인 텍스트에 의존하는 게이트에는 명령어를 작성할 수 있는 방법만큼이나 많은 구멍이 있다는 증거이기도 합니다. 다음 문구는 다시 빠져나갈 수 있습니다. 그러니 되돌릴 수 없는 작업을 단 하나의 권한 검사 같은 그물망에 맡기지 마세요. 여러 층으로 방어하세요.
- 삭제하기 전에 확인하세요. 무엇을 삭제할지 목록화하는 습관을 들이세요.
find를 사용할 때는 삭제 동작 없이 실행하여 목록만 확인하세요.git clean을 사용할 때는 커밋하기 전에 드라이런(dry run)을 하세요. - 삭제될 것이라고 가정하고, 탈출구를 만드세요. 위험한 작업을 수행하기 전에 브랜치를 분기하고, 커밋하고, 백업을 받으세요. 그물망이 무력화되더라도, 잃어버린 것은 복원할 수 있는 범위 안에 남아있습니다.
- 대상을 명시적으로 지정하세요; 변수에 의존하지 마세요. #75859의 핵심은 삭제 대상을 변수(
$HOME)에 맡긴 것이었습니다. 변수는 예상치 못한 값으로 해석될 수 있습니다. 서브디렉토리를 알고 있다면, 상대 경로 이름으로 대상을 지정하세요 —rm -rf ./build와 같이 오직 한 가지로만요. - 설정, 실행, 복구를 독립적으로 유지하세요. 사전 실행 단계의 그물망(권한 검사 또는 저의 후크 같은 것)은 여러 층 중 하나일 뿐입니다. 위험한 도구 호출 자체를 허용하지 않는 설정 계층, 실행 직전에 이를 막는 계층, 그리고 둘 다 우회하더라도 복원할 수 있게 해주는 복구 계층을 독립적으로 만드세요.
솔직히 말해서: 저의 무료 후크인 cc-safe-setup은 여전히 해당 2>/dev/null 형태를 통과시키며, 위 표에서 볼 수 있듯이 (단순한 위험 삭제는 막습니다). 그래서 저는
원한다면 두 가지 무료 자료를 드립니다:
- 실행 직전에 이 유형의 사고를 막아주는 설정 및 후크(config-and-hooks):
npx cc-safe-setup(MIT). - 해당 월에 Claude Code에서 조용히 무엇이 고장 났는지, 그리고 이를 방지하기 위한 설정을 담은 무료 월간 노트: Claude Code Safety Brief.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기