Claude Code로 API 키가 유출되는 것을 방지하는 방법
요약
Claude Code 사용 중 API 키가 프롬프트나 세션 기록에 노출되는 문제를 해결하기 위한 오픈 소스 플러그인 'Keyward'를 소개합니다. Keyward는 훅(hook)을 통해 키를 탐지하고, OS 레벨의 자동화를 활용해 키를 안전한 참조값으로 교체하여 재전송합니다.
핵심 포인트
- Claude Code의 UserPromptSubmit 훅은 프롬프트 재작성이 불가능하고 차단만 가능함
- Keyward는 키를 탐지하여 로컬에 안전하게 저장하고 프롬프트 내 키를 참조값으로 대체함
- OS 레벨 자동화를 통해 차단된 프롬프트를 정화된 텍스트로 자동 재전송하는 우회 방식 사용
- API 키 유출 방지를 위한 자동화된 보안 워크플로우 제공
Claude Code에 API 키를 붙여넣을 때마다 다음과 같은 작은 경고가 떴습니다: "이 키가 유출되었을 수 있습니다 — 키를 교체(rotate)하세요.""
그리고... 네, 알고 있습니다. 그 시점에는 이미 키가 요청(request)에 포함되어 있고, 제 세션 기록(session transcript)에 영원히 남게 됩니다. 키를 교체하는 것은 사후 처리일 뿐, 근본적인 해결책이 아닙니다.
키를 참조할 때마다 매번 교체하고 싶지는 않았고, "그냥 조심하자"라는 다짐은 속도를 내어 작업하는 순간 — 즉, 바이브코딩(vibecoding)을 하고 있는 대부분의 시간 — 무용지물이 됩니다. 그래서 저는 '조심하는 부분'을 자동화하기로 했습니다.
그것의 이름은 Keyward입니다 — 작고 오픈 소스인 Claude Code 플러그인입니다. 여기 그 아이디어와, 이를 제작하면서 직면했던 정말 까다로웠던 부분에 대해 설명하겠습니다.
정확한 문제점
채팅에 비밀 값(secret)을 붙여넣으면 다음과 같은 일이 발생합니다:
- 프롬프트(prompt)의 일부로서 Anthropic의 API로 전송됩니다.
- 로컬의
*.jsonl기록(transcript)에 기록됩니다. - Claude가 (정확하게) 유출되었다고 알려줍니다.
한 번의 붙여넣기로 세 곳에 영향을 미칩니다. 경고를 다 읽기도 전에 이미 피해는 발생한 상태입니다.
Keyward가 하는 일
UserPromptSubmit 훅(hook)이 사용자가 제출하는 모든 메시지를 스캔합니다. 키를 발견하면 다음과 같이 동작합니다:
- 탐지(detects): 약 20개의 제공업체에 대한 정규 표현식(regex), 명시적인
/key마커, 선택적인 gitleaks를 사용합니다. - 저장(saves): 값을
~/.claude/secrets/<name>.txt에 저장합니다 (chmod 600). - 차단(blocks): 원본 프롬프트를 차단하여 가공되지 않은 값이 모델에 도달하지 않도록 합니다.
- 재전송(re-submits): 메시지의 정제된(sanitized) 버전을 다시 제출합니다 — 키는
<<secret:NAME stored at ~/.claude/secrets/NAME.txt>>로 대체됩니다.
사용자는 Enter를 한 번만 누르면 되며, 모델은 오직 참조값만을 보게 됩니다.
까다로운 부분: 프롬프트를 수정할 수 없고, 오직 차단만 가능하다
이 부분은 저를 놀라게 했기에 공유할 가치가 있습니다.
Claude Code의 UserPromptSubmit 훅은 메시지가 모델에 도달하기 전에 실행되므로, 키를 잡아내기에 완벽한 장소입니다. 하지만 설계상, 해당 훅은 프롬프트를 다시 작성(rewrite)할 수 없습니다. 오직 다음 작업만 가능합니다:
- 프롬프트와 함께 컨텍스트를 추가하거나,
- 프롬프트를 완전히 **차단(block)**하는 것.
이는 의도적인 안전 설계입니다. 프롬프트를 조용히 재작성할 수 있는 훅(hook)은 매우 위험한 공격 표면(attack surface)이 될 수 있기 때문입니다 (예를 들어, 플러그인이 사용자의 "파일 X 삭제"를 몰래 "파일 Y 삭제"로 바꾸는 상황을 상상해 보십시오).
따라서 "키를 감지하고 조용히 교체하는 것"은 직접적으로 불가능합니다. Keyward의 우회 방법은 다음과 같습니다:
# intercept.py (단순화 버전)
detection = detect(prompt)
if detection["secrets"]:
...
이 훅은 유출될 프롬프트를 차단(block)하고, **OS 레벨의 자동화 (OS-level automation)**를 통해 정화된(sanitized) 텍스트를 붙여넣고 Enter 키를 대신 눌러주는 아주 작은 분리된 프로세스를 생성합니다. 사용자 입장에서는 차단된 메시지가 깜빡인 후, 깨끗한 메시지가 그 자리를 대신하게 됩니다. 키 입력은 단 한 번뿐입니다.
크로스 플랫폼 붙여넣기 (Cross-platform paste)
붙여넣기 백엔드는 OS별로 다르며, 각 백엔드는 클립보드를 저장하고, 타이핑하고, 포커스가 변경되지 않았는지 확인한 후 클립보드를 복구합니다:
- macOS —
osascript(손쉬운 사용(Accessibility) 권한 필요) - Linux X11 —
xdotool - Linux Wayland —
wtype(컴포지터(compositor)에 따라 다름: Sway/Hyprland는 지원, GNOME은 기본적으로 미지원) - Windows — PowerShell
SendKeys
디스플레이 서버가 없는 경우(SSH, Docker)? KEYWARD_DISABLE_PASTE=1로 설정하십시오. 데이터는 여전히 저장 및 정화되지만, 붙여넣기는 수동으로 수행해야 합니다.
재유출 없이 저장된 키 사용하기
내장된 기술을 통해 Claude가 비밀 정보를 출력하지 않고 소비하도록 학습시킵니다:
export GITHUB_TOKEN=$(cat ~/.claude/secrets/github_pat_classic.txt) && gh api /user
...절대로 생으로 cat 명령어를 사용하지 않습니다 (이는 값을 컨텍스트로 곧바로 덤프하게 됩니다). 값은 디스크 → 프로세스 환경 변수(process env) → 도구(tool)로 흐르며, 표준 출력(stdout)을 통해서는 절대 전달되지 않습니다.
솔직히 말해서: 이것은 마법이 아니라 심층 방어 (defense-in-depth)입니다
비밀 정보는 chmod 600 권한의 평문으로 저장됩니다. 이는 ~/.aws/credentials나 .env 파일과 동일한 신뢰 모델이며, 저장 시 암호화(encrypted at rest)되지는 않습니다. Keyward는 **"지금 당장 채팅에서 이 키를 한 번 사용해야 해"**라는 워크플로우를 위한 안전망이지, 실제 비밀 관리자(secret manager)를 대체하는 것이 아닙니다. README와 위키(wiki)에는 이 도구가 무엇을 보호하고 무엇을 보호하지 않는지가 정확히 문서화되어 있으며, 이는 보안 도구로서 올바른 방향이라고 느껴집니다.
시도해 보기
Claude Code 세션에서:
/plugin marketplace add albemiglio/keyward
/plugin install keyward@keyward
자유 및 오픈 소스 (MIT) — github.com/albemiglio/keyward. 약 35개의 테스트, macOS/Linux/Windows 전반에 걸친 CI(지속적 통합), 네트워크 호출 없음, 텔레메트리 (Telemetry) 없음.
만약 AI 도구에 키를 붙여넣고 결과가 좋기만을 바랐던 적이 있다면 — 이것이 바로 그 안전망입니다. 🔑
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기