AI 코딩 에이전트 시크릿 키 유출 방지 — 새는 길 3곳
3.2% 대 1.5%. GitGuardian이 2025년 공개 GitHub 커밋을 훑어보니, Claude Code가 관여한 커밋에서 시크릿이 새는 비율이 전체 평균의 두 배를 넘었다. 공격자가 있어야 벌어지는 사고가 아니다. 설정 파일 하나, 대화 한 줄로 충분하다.
금요일 오후, 팀원이 새 MCP 서버를 붙인다. 터미널에 한 줄 입력하자 프로젝트 루트에 .mcp.json이 생기고, 그 안에 방금 붙여 넣은 API 키가 평문으로 박힌다. Claude Code 공식 문서는 이 파일을 버전 관리에 커밋해 팀과 공유하라고 안내한다. 다음 주 월요일, 그 키는 원격 저장소에 올라가 있다.
이 글은 AI 코딩 에이전트 시크릿 키 유출 방지에 집중한다. 2026년 6월 Tenet Security가 명명한 '에이전트재킹(agentjacking)'은 Sentry MCP에 가짜 오류를 심어 에이전트가 코드를 실행하게 만드는 공격이다. 그런 실행 권한 탈취는 프롬프트 인젝션 글에서 따로 다뤘다. 여기서 다룰 건 더 조용한 쪽, 아무도 공격하지 않았는데 키가 밖으로 걸어 나가는 경로다.
숫자로 보면: 에이전트가 붙은 곳에서 더 샌다
GitGuardian은 매년 공개 GitHub 전체를 스캔해 State of Secrets Sprawl 보고서를 낸다. 2026년 3월판(2025년 데이터)과 전년판 수치를 한 표에 모았다.
| 지표 | 수치 | 출처 |
|---|---|---|
| 공개 GitHub 신규 하드코딩 시크릿 | 2,865만 건 (전년 대비 +34%) | GitGuardian 2026 |
| AI 서비스 키 유출 | 127만 5,105건 (+81%) | GitGuardian 2026 |
| 공개 MCP 설정파일 속 시크릿 | 24,008건, 그중 유효 2,117건 | GitGuardian 2026 |
| Claude Code 보조 커밋 유출률 | 3.2% (전체 기준선 1.5%) | GitGuardian 2026 |
| Copilot 활성 저장소 유출률 | 6.4% (전체 4.6%, 약 40% 높음) | GitGuardian 2025, 약 2만 개 저장소 표본 |
눈여겨볼 줄은 MCP다. MCP가 2024년 11월 공개된 뒤 첫 한 해 남짓 만에 2만 4천 건이 공개 저장소에 올라왔다. 보고서는 MCP 서버 문서 상당수가 인증 정보를 설정 파일에 직접 넣으라고 안내한다는 점을 원인으로 짚는다. 도구를 탓하기 전에 예제 코드가 문제였던 셈.
키가 새는 길 세 곳
① "일단 돌아가게" — 하드코딩
에이전트에게 "결제 API 붙여줘"라고 하면, 동작하는 코드를 가장 빨리 만드는 방법은 키를 소스에 바로 쓰는 것이다. 사람이 리뷰 없이 수락하면 그대로 커밋된다. Copilot 활성 저장소의 6.4%라는 수치도 이 경로와 무관해 보이지 않는다. AI 서비스 키 유출이 81% 급증했다는 대목도 같은 맥락. 보고서는 DeepSeek API 키만 11만 3천 건이 샜다고 적었다.
② 공유하라고 만든 파일 — MCP 설정
경로를 외워 두자. Claude Code는 프로젝트용 .mcp.json과 사용자용 ~/.claude.json, Cursor는 .cursor/mcp.json과 ~/.cursor/mcp.json을 쓴다. 프로젝트 쪽 파일은 팀 공유가 설계 목적이라 .gitignore로 숨기면 팀원마다 설정을 따로 맞춰야 한다. 그러니 파일은 커밋하고, 키는 변수로 빼는 게 정답이다.
// .mcp.json (Claude Code) — 키 자리에 변수만
{
"mcpServers": {
"billing": {
"type": "http",
"url": "https://api.example.com/mcp",
"headers": { "Authorization": "Bearer ${BILLING_API_KEY}" }
}
}
}
// Cursor .cursor/mcp.json 은 "${env:BILLING_API_KEY}" 문법,
// stdio 서버라면 "envFile" 필드로 별도 파일 지정 가능
③ 컨텍스트로 빨려 들어가는 .env
세 번째는 커밋조차 필요 없다. 2026년 1월 The Register는 Claude Code v2.1.12에서 .claudeignore에 .env를 적어 두었는데도 에이전트가 파일을 읽어 비밀값을 출력하는 현상을 재현했다. 읽힌 값은 모델 컨텍스트, 즉 외부 서버로 가는 요청에 실린다. GitGuardian은 2026년 9월 분석에서 셸 히스토리, 에이전트 로그(~/.copilot/logs/ 등), 캐시까지 저장소 스캐너가 보지 못하는 흔적으로 꼽았다.
"ignore 파일이면 된다"는 착각
가장 흔한 처방은 .cursorignore나 권한 거부 규칙이다. 필요하다. 그런데 공식 문서를 끝까지 읽으면 벤더 스스로 한계를 적어 두었다.
Cursor 문서: Agent가 쓰는 터미널과 MCP 서버 도구는 .cursorignore로 막을 수 없고, LLM의 예측 불가능성 때문에 완전한 보호는 보장되지 않는다.
Claude Code 문서: Read 거부 규칙은 내장 파일 도구와 cat·head 같은 인식 가능한 명령에 적용된다. 파일명을 지정하지 않는 grep -r, 스스로 파일을 여는 Python·Node 스크립트에는 적용되지 않는다. 모든 프로세스를 막으려면 샌드박스를 켜라고 안내한다.
여기서 두 진영이 갈린다. "규칙을 촘촘히 짜면 된다"는 쪽과 "디스크에 키가 있는 한 언젠가 읽힌다"는 쪽. 나는 후자에 가깝다. 거부 규칙은 사고 확률을 낮추는 안전벨트다. 사고 자체를 없애려면 읽을 파일이 애초에 없어야 한다. 시크릿 매니저에서 실행 시점에만 주입하면 에이전트가 .env를 열어 봐야 빈 껍데기다.
물론 비용이 있다. 로컬 개발마다 매니저 인증을 거쳐야 하고, 1인 프로젝트엔 과할 수 있다. 그래서 아래 체크리스트는 층을 나눴다.
개발팀 방지 체크리스트
오늘 바로 할 것부터. 먼저 Claude Code를 쓰는 팀이라면 공유 설정에 거부 규칙을 넣는다. 공식 문서 예시 그대로다.
// .claude/settings.json
{
"permissions": {
"deny": ["Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)"]
}
}
- MCP 설정은 변수만 —
.mcp.json·.cursor/mcp.json에 평문 키가 있으면${VAR}형태로 교체하고, 이미 커밋된 키는 즉시 폐기·재발급. - pre-commit 스캔 — gitleaks나 ggshield 같은 시크릿 스캐너를 커밋 훅과 CI 양쪽에 건다. 에이전트가 만든 커밋도 같은 문을 지나게.
- ignore와 deny는 둘 다 —
.cursorignore, Claude Codepermissions.deny를 함께 쓰되 "보장 아님"을 전제로. - 샌드박스 켜기 — 셸 명령과 하위 프로세스의 파일 접근을 OS 수준에서 제한.
- 키 수명 줄이기 — 개발용 키는 권한 최소·짧은 만료. 새도 피해 반경이 작다.
- 로컬 흔적 점검 — 셸 히스토리, 에이전트 로그 폴더에 키가 찍혔는지 분기마다 확인.
우선순위 한 줄 요약 — 1인·사이드 프로젝트는 변수화 + pre-commit 스캔까지. 팀·고객 데이터가 걸린 저장소는 샌드박스와 시크릿 매니저까지 올린다.
숫자가 말해 주는 건 에이전트가 부주의하다는 사실이 아니다. 키를 두는 자리가 코드에서 작업 공간 전체로 넓어졌다는 것이다. 당신의 저장소에서 mcp.json을 검색해 보면 어떤 줄이 나올까. 한 번 확인해 보면 답이 나온다.
참고: GitGuardian State of Secrets Sprawl 2026·2025, GitGuardian 블로그(2026-09-25), The Register(2026-01-28), Cursor·Claude Code 공식 문서.