검색 명령 하나가 PC를 멈춘 날과 그 뒤에 만든 안전장치
AI가 돌린 grep 하나가 메모리 61GB를 먹고 PC를 멈춰 세웠어요. 원인을 찾은 과정과 같은 일을 기계가 막도록 만든 훅 두 개를 보여 드려요.
1단계부터 보기 · 모두 7단계«이런 명령은 쓰지 마»라고 규칙에 적는 것보다, 명령이 실행되기 직전에 걸러 내는 훅을 하나 두는 편이 확실해요.
차례
한 화면에 한 단계씩 넘기며 보세요.
한 쪽에 모두 보기
2026년 9월 29일, 운영자가 출근해 있는 동안 집 PC 화면이 까맣게 변하고 오류 창이 잔뜩 떴어요. 저녁에 돌아왔을 때는 «바이러스로부터 보호할 수 없습니다»라는 경고까지 떠 있었어요. 운영자는 바로 이렇게 시켰어요. «컴퓨터 로그 확인해서 무슨일이 있었는지 추적해».
Claude Code에 작업을 맡겨 두고 자리를 비우는 분이라면 남 일이 아니에요. AI가 돌린 명령 하나가 PC 전체를 멈출 수 있거든요.
로그에서 찾은 것
윈도우 이벤트 로그를 시간순으로 따라가 보니 이런 일이 있었어요. 11시 49분부터 메모리 고갈 경고가 9번 떴고, grep.exe 하나의 가상 메모리가 56.7GB에서 61.6GB까지 불어났어요. 백신의 실시간 보호도 멈췄고, 저녁에 본 경고는 그 뒤로 30분마다 뜬 «백신 꺼짐» 알림이었어요. PC는 19시 9분에 비정상 종료됐어요.

바이러스를 잡았다는 기록은 하나도 없었어요. 원인은 악성 코드와 상관없이 메모리가 바닥난 데 있었어요.
누가 grep을 돌렸나
이 부분은 끝내 확정하지 못했어요. 프로세스를 누가 띄웠는지 남기는 윈도우 기록이 꺼져 있었거든요.
다만 같은 시간대에 다른 작업 창의 Claude가 .{300}이나 .\{600\}처럼 반복 횟수가 큰 정규식으로 큰 텍스트 파일을 여러 번 검색한 기록이 있었어요. GNU grep은 이런 큰 반복을 처리하면서 메모리를 크게 부풀릴 수 있어서, 그 검색이 원인이었을 것으로 보고 있어요.
또 하나 알게 된 것이 있어요. AI 쪽 명령은 시간 제한에 걸려 끝났다고 표시돼도, 실제 grep.exe는 뒤에 남아 계속 돌 수 있어요. 명령을 건 쪽만 끝나고 프로세스는 고아로 남는 거예요.
운영자가 내린 결론
로그를 보고 난 운영자의 말은 짧았어요. «근데 이게 grep이거를 사용하고 종료하는 규칙을 잘 세우면되는거아니야?»
글로 «큰 반복 쓰지 마»라고 적어 두는 방법은 이미 여러 번 새 봤어요. 그래서 이번에는 Claude Code의 훅(hooks)으로 기계가 막게 했어요. 훅은 Claude가 도구를 쓰기 직전이나 답을 마친 직후처럼 정해진 순간에 내 스크립트를 자동으로 돌려 주는 기능이에요.
만든 안전장치

- 실행 전에 막는 훅이에요. Claude가 셸 명령을 실행하기 직전(
PreToolUse)에 명령 문자열을 받아 보고, grep 식에 100 이상의 반복이 있거나 드라이브 전체를 재귀 검색하면 거부해요. 거부 이유와 함께 «파이썬으로 필요한 부분만 잘라 읽거나 반복을 100 아래로 줄이라»는 대안도 돌려줘요. - 남은 프로세스를 치우는 훅이에요. Claude가 답을 마칠 때(
Stop)와 세션을 시작할 때(SessionStart)마다, 10분 넘게 돌았거나 메모리를 4GB 넘게 먹은 grep 프로세스를 찾아 꺼요. 다른 프로그램은 건드리지 않아요.
첫째 훅을 줄여 보면 이래요. 파이썬 파일 하나로 끝나요.
# 큰 반복 정규식과 드라이브 전체 grep -r 을 실행 전에 거부한다
import json, re, sys
cmd = str((json.load(sys.stdin).get("tool_input") or {}).get("command", ""))
why = None
if re.search(r"\b[ef]?grep\b", cmd):
nums = [int(n) for n in re.findall(r"\\?\{\s*(?:\d+\s*,\s*)?(\d+)\s*\\?\}", cmd)]
if nums and max(nums) >= 100:
why = f"grep 식에 반복 {max(nums)}회, 메모리가 크게 불어날 수 있음"
elif re.search(r"grep\b.*\s-\w*[rR]\w*\b.*\s(/|c:[/\\]?|~/?)(\s|$)", cmd, re.I):
why = "드라이브 전체를 뒤지는 grep -r"
if why:
print(json.dumps({"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": why + ". 필요한 부분만 파이썬으로 잘라 읽거나 폴더를 좁히세요."}}, ensure_ascii=False))
등록은 ~/.claude/settings.json에 이렇게 해요.
{
"hooks": {
"PreToolUse": [
{ "matcher": "Bash", "hooks": [ { "type": "command", "command": "python ~/.claude/hooks/no_runaway_grep.py" } ] }
]
}
}
등록한 뒤에는 일부러 위험한 명령을 시켜 보고 정말 거부되는지 확인하세요. 이 사례에서는 시험 명령 10건으로 거부와 통과를 모두 확인한 뒤에 썼어요. 아래는 이 글의 코드에 명령 세 개를 넣어 실제로 돌린 결과예요.

다음 날 생긴 일
같은 방식으로 «코덱스를 두 개 동시에 돌리지 마»라는 규칙도 훅으로 만들었는데, 처음에는 사람에게 «계속할까요?»라고 묻는 방식이었어요. 그랬더니 승인 창이 뜰 때마다 작업이 멈췄어요. 운영자는 9월 30일에 이렇게 말했어요. «나는 승인땜에 레포가 멈추는 걸 진짜 넘 싫어해».
그래서 묻지 않고 판단하게 바꿨어요. 부모 프로세스가 이미 죽은 것이나 40분 넘게 CPU를 쓰지 않고 멈춰 있는 것은 훅이 직접 끄고, 정상으로 일하는 중이면 «끝나면 다시 시도»로 돌려보내요. 사람에게는 결과만 알려요.
이 일로 생긴 규칙
- 잴 수 있는 규칙은 글로 적지 않고 훅으로 만들어요.
- 훅은 되도록 사람에게 묻지 않고, 기계가 판단할 수 있는 조건으로 막거나 치워요.
- 큰 파일에서 앞뒤 문맥이 필요하면 grep에 큰 반복을 걸지 말고 파이썬으로 필요한 만큼만 잘라 읽어요.
근거
- Claude Code 공식 문서, Hooks · 2026-10-10 확인
- 시각과 메모리 수치는 사고 당일 윈도우 이벤트 로그에서 확인한 값이에요. grep을 돌린 쪽이 누구인지는 확인하지 못했어요.
이 글을 만든 방법
- 바탕운영자가 실제로 돌린 작업의 기록(작업 일지·설정 파일·오류 기록)
- 쓴 쪽AI(Claude)가 썼어요
- 독립 검수2026-10-10에 쓴 AI와 다른 AI가 원본과 대조해 통과시켰어요
- 사실 확인2026-10-10
발행 2026-10-10