개발 루프 안의 LLM 이 시크릿을 위험에 빠뜨리는 방법이 다섯 가지야. 경로를 아는 게 방어의 절반이고.
1. 직접 파일 읽기
Agent 가 Read 도구 가짐. "내 deploy 어떻게 생겼어?" 물음. Agent 가 context 위해 docker-compose.yml + .env 읽음. .env 내용이 이제 모델의 context window 에 들어갔어. 그 말은 API 요청에 실렸다는 뜻이고, 결국 네 통제 밖 서버에 있다는 뜻이야.
2. 도움 되는 echo
Stack trace 붙여넣음. trace 에 비밀번호 박힌 connection string 포함. 모델이 에러를 요약해줘. "Postgres at postgres://app:HUNTER2@db.internal:5432/prod 가 connection 을 거부하고 있습니다". 이제 비밀번호가 채팅 transcript 에 남았어.
3. Reasoning-trace 누출
최근 reasoning 모델 (o-series, Claude thinking, DeepSeek R1, Gemini Thinking 등) 이 종종 *thinking* 블록 생성. 그 블록은 사용자한테 보이기도 하고, 숨겨지기도 하고, 따로 로그에 남기도 해. 많은 제품이 billing 이나 QA 를 위해 trace 를 서버로 올려보내고. 모델이 "비밀번호가 HUNTER2 라고 밝히면 안 된다" 고 생각하는 순간, 그 문자열이 그대로 trace 에 박혀.
4. 하드코딩하는 제안 코드
"DB 연결하는 스크립트" 요청. 모델이 친절하게도 방금 context 에서 본 비밀번호를 채워 넣어. 제안을 받아들이면 이제 시크릿이 commit 된 코드에, 디스크에, 그리고 git 히스토리는 영원하니까 repo 의 영구 기록에 남아.
5. Cross-conversation bleed (memory 기능)
요즘 assistant 의 "Memory" 기능은 session 을 넘어 사실을 저장해둬. session A 가 (.env 를 읽어서) API key 를 알게 되면, session B 가 그걸 떠올릴 수도 있어.
| 벡터 | 시크릿이 끝나는 곳 | cleanup 가장 어려운 부분 |
|---|---|---|
| 직접 파일 읽기 | API 요청, provider 로그, 가능하면 훈련 데이터 | 삭제 완전히 증명 못 함 |
| 도움 되는 echo | 채팅 transcript, 스크린샷, 공유 | 어디까지 퍼졌는지 통제 불가 |
| Reasoning trace | Trace 로그, billing 시스템 | 사용자 눈에 아예 안 보이는 경우가 많음 |
| 제안에 하드코딩 | 네 repo, git 히스토리, deploy artifact | Git 히스토리 rewrite 는 고통스럽고 부분적 |
| Memory bleed | provider 의 persistent memory store | 감사도 어렵고 골라서 지우기도 어려움 |