
`/clear` 사용 시 세션 ID가 변경되어 직접 만든 안전 hook이 조용히 작동하지 않게 되는 문제 — SessionStart 전제의
요약
Claude Code에서 `/clear` 명령 사용 시 세션 ID가 변경되어, `SessionStart`에서 설정한 안전 hook이 무력화될 수 있는 보안 취약점을 설명합니다. 에러 없이 조용히 작동하지 않으므로 'fail closed' 설계의 중요성을 강조합니다.
핵심 포인트
- /clear 사용 시 내부 세션 ID가 새로 재할당됨
- SessionStart hook은 /clear 이후 재실행되지 않음
- 새로운 ID에 대한 상태값이 없어 안전 hook이 무력화될 위험
- 보안을 위해 상태 부재 시 차단하는 'fail closed' 방식 권장
Claude Code에서 안전을 위한 hook(예: PreToolUse에서 위험한 조작을 차단하는 종류)을 작성하고 있는 분들을 위한 이야기입니다. /clear를 사용한 뒤에 해당 hook이 조용히 작동하지 않게 되는 경우가 있다는 함정을, 이슈 보고와 hook의 표준 메커니즘을 통해 정리합니다. 에러가 발생하지 않기 때문에 알아차리기 어렵고, 알아차렸을 때는 "지키고 있다고 생각했지만 아무것도 지키지 못하고 있었다"는 상황이 되어 매우 위험합니다.
/clear로 세션의 문맥(context)을 버리면, 내부적으로 세션 ID(session_id)가 새로 재할당된다는 동작이 보고되었습니다 (anthropics/claude-code#70606).- 반면, 기동 시에 한 번만 실행되는
SessionStarthook은/clear이후에는 재실행되지 않습니다. - 따라서 "
SessionStart에서 세션별 상태를 준비하고,PreToolUse에서 그 상태를 확인하여 가부를 판단한다"는 구조의 hook은,/clear이후에 "준비했을 터인 상태를 찾을 수 없는" 상태에 빠지게 됩니다. - 이때 hook이 "찾을 수 없음 = 해당 사항 없음 = 통과"라고 작성되어 있다면, 안전 hook이 아무것도 차단하지 않게 됩니다. 게다가 에러도 발생하지 않습니다.
보고에 따르면, 세션별 경로를 검증하는 hook이 /clear 이후 3일 동안, 아무도 모르는 사이에 오작동을 지속했다고 합니다.
Claude Code의 hook에는 실행되는 장면(이벤트)이 있습니다. 안전을 위한 hook에서 자주 사용하는 것은 다음 두 가지입니다.
SessionStart: 세션이 시작될 때 한 번만 실행됩니다. 임시 디렉터리를 만들거나, 인가(authorization) 방침을 읽어오는 등의 "준비"를 여기서 수행합니다.PreToolUse: 도구(tool)를 실행하기 전에 매번 실행됩니다.Bash명령어나 파일 쓰기를 확인하여, 위험할 경우 종료 코드2로 중단시킵니다.
session_id는 두 hook 모두에 전달되는 입력에 포함됩니다. 정석적으로 설계한다면, SessionStart에서
/tmp/claude-session-<session_id>/
와 같은 장소에 방침이나 기록을 준비하고, PreToolUse에서는 전달받은 session_id로부터 동일한 장소를 구성하여 읽는 형태가 됩니다. 여기까지는 자연스럽습니다.
문제는 /clear입니다. 보고에 따르면, /clear 시에 내부적으로 세션 ID가 새로 재할당됩니다. 그러면,
/clear이후의PreToolUse에는 새로운session_id가 전달됩니다.- 하지만
SessionStart는 재실행되지 않습니다. 새로운 ID에 대응하는/tmp/claude-session-<새로운ID>/는 만들어지지 않은 상태입니다. PreToolUsehook은 새로운 ID로부터 구성한 장소를 확인하러 가지만, 그곳에는 아무것도 없습니다.
여기서 hook의 작성 방식에 따라 결과가 갈립니다.
- 상태가 없을 때 통과시킨다(fail open)고 작성된 경우: 모든 조작이 그대로 통과됩니다. 안전 hook이 무효화된 것과 같습니다.
- 상태가 없을 때 차단한다(fail closed)고 작성된 경우: 모든 것이 거부됩니다. 작업은 중단되지만, 위험은 통과시키지 않습니다 (번거롭지만 안전한 쪽입니다).
추가로, CLAUDE_ENV_FILE에 작성한 환경 변수는 hook의 자식 프로세스로 전달되지 않기 때문에, hook 측에서 "새로운 ID를 이전 ID로 치환"하는 등의 복구도 정석적인 방법으로는 불가능하다는 점도 보고에서 언급되었습니다.
/clear는 문맥을 정리하기 위해 일상적으로 누르는 조작입니다. 누른 후에도 화면은 정상적으로 작동합니다. hook은 종료 코드 0(문제 없음)을 반환하며 조용히 통과시키므로, 로그에도 이상이 남지 않습니다. 방어막이 풀렸다는 사실 자체가 무증상이며, 다음에 정말 위험한 조작이 왔을 때, 그것도 막지 못하고 통과해 버린 뒤에야 깨닫게 됩니다.
다음 사항에 모두 해당한다면, 위험 범위에 들어와 있습니다.
SessionStart에서 임시 디렉터리, 락 파일(lock file), 인가 방침 등 세션별 상태를 준비하고 있다.PreToolUse에서 그 상태를 보고 가부를 판단하고 있다 (특히session_id...
(경로를 구성하여 읽고 있다). - 세션 중에 /clear를 사용하는 경우가 있다.
반대로, 전달된 커맨드나 파일 경로만을 보고 그 자리에서 가부를 결정하는 '상태를 가지지 않는 (stateless)' hook은 영향을 받지 않습니다. tool_input을 읽어 그 자리에서 판단하는 구조라면, session_id가 바뀌어도 동작은 변하지 않습니다. 먼저 확인해야 할 것은 자신의 안전 hook이 상태를 가지고 있는지 여부입니다.
제공 측의 대응( /clear 이후에 SessionStart를 다시 호출하는 등)을 기다리기 전에, 작성하는 측에서 자위할 수 있습니다. 원칙은 하나, 안전을 위한 hook은 판단에 필요한 상태를 찾을 수 없을 때, 통과시키는 쪽이 아니라 차단하는 쪽으로 기울어야 한다 (fail-closed).
#!/bin/bash
# 상태가 없을 때는 통과시키지 않고 차단한다 (matcher는 "Bash" 등)
INPUT=$(cat)
...
번거롭게 느껴지더라도, 방어 기제가 조용히 해제되어 위험한 조작을 통과시키는 것보다, 차단되어 인지할 수 있는 편이 더 안전합니다.
차단되는 것이 업무상 힘들다면, SessionStart에 전적으로 의존하지 말고 PreToolUse에서 "없으면 만든다"와 같이 처리합니다.
if [ ! -d "$STATE_DIR" ]; then
mkdir -p "$STATE_DIR"
printf 'deny\n' > "$STATE_DIR/policy" # 기본값은 반드시 안전한 쪽으로 (없으면 거부)
...
다시 만들 때의 기본값을 "전부 허용"으로 설정하면 fail-open으로 되돌아가므로, 반드시 안전한 쪽으로 설정합니다.
가장 잘 망가지지 않는 것은 세션의 상태에 의존하지 않는 hook입니다. 가부 판단이 tool_input (커맨드 문자열, 파일 경로)만으로 완결된다면, session_id가 바뀌어도 아무 일도 일어나지 않습니다. 새로 hook을 작성할 때는 상태를 넘나들 필요가 정말로 있는지부터 의심해 보십시오.
/clear는 세션의 ID를 새로 부여하지만, SessionStart는 재실행되지 않습니다. 따라서 세션의 상태를 전제로 하는 안전 hook은 /clear 이후에 조용히 작동하지 않게 될 수 있습니다 —— 게다가 에러가 발생하지 않으므로 알아차릴 수 없습니다. 방어용 hook은,
상태를 찾을 수 없을 때 통과시키지 않고 차단(fail-closed)하거나, 그 자리에서 안전한 쪽으로 다시 만든다. 가장 확실한 것은,
상태를 가지지 않는 것입니다.
tool_input만으로 판단하는 hook을 선택하십시오. 무료로 공개되어 있는 안전 hook 모음인 cc-safe-setup의 hook은 대부분 tool_input을 보고 그 자리에서 판단하는 '상태를 가지지 않는' 구조이므로, 이 /clear 문제의 영향을 받지 않습니다 (위험한 Bash, 파일 전체 치환, git의 파괴적인 조작 등을 실행 전에 차단합니다). 우선 자신의 환경에 설치하여 토대를 다지는 용도로 사용할 수 있습니다.
"어떤 사고가 어떤 설정으로 방지될 수 있는가"를 실제로 발생한 이슈(issue)로부터 역산하여 순서대로 정리한 유료 도서도 출간했습니다 (Claude Code 사고 방지 도서 · ¥800 · 3장까지 무료 · 총 51장). 이 /clear로 인해 안전 hook이 조용히 작동하지 않게 되는 이야기는 그중 제51장으로 수록되어 있습니다. Kindle 버전(Kindle Unlimited 대응)으로도 읽을 수 있습니다.
본 기사 중, /clear가 세션의 ID를 새로 부여하지만 SessionStart가 재실행되지 않는 동작은 이슈 #70606의 보고와 코멘트에 기반한 것입니다 (필자 자신이 일으킨 사고는 아닙니다). session_id가 hook의 입력에 포함된다는 점, PreToolUse가 종료 코드 2로 조작을 중단할 수 있다는 점, SessionStart가 준비를 위한 이벤트라는 점은 hook의 표준 메커니즘에 기반하여 작성되었습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기