Claude Code나 다른 AI 코딩 에이전트를 쓰고 있다면, 먼저 10분만 내 레포지토리를 점검하세요. 커밋된 에이전트 설정 파일을 검색하고, 거기에 들어 있는 모든 자격 증명을 교체(rotate)하고, GitHub의 secret scanning을 켜세요. 탈취된 키는 순식간에 되팔립니다(Unit 42는 몇 분 만에 벌어진 사례를 소개합니다). 그래서 이야기보다 점검이 먼저입니다.
먼저 내 레포에서 이 점검들을 실행하세요
Claude Code 사건의 중심에 있는 파일 .claude/settings.local.json부터 시작합니다. 보안 업체 Apiiro는 공개 레포지토리 103,617개에서 이 파일 사본 104,185개를 찾았고, 그중 1,122개에 시크릿이 하나 이상 들어 있었습니다(The Hacker News). 내 레포를 확인하는 방법은 다음과 같습니다.
- GitHub 조직 전체에서 파일 이름으로 검색합니다(조직 이름은 본인 것으로 바꾸고, GitHub CLI가 필요합니다).
- 작업 중인 각 레포에서 이 파일이 한 번이라도 커밋된 적이 있는지 오래된 브랜치까지 포함해 확인합니다. 최신 커밋에서 지워도 히스토리에는 남아 있습니다.
- 저장된 승인 항목에서 비밀번호, 토큰, 연결 문자열처럼 보이는 것이 있는지 읽어봅니다.
- 전체 히스토리를 스캔하고, 기본 규칙 세트가 놓치기 쉬운 명령어 안에 입력된 비밀번호를 잡는 규칙을 추가합니다.
# 1. Find the files across an organization
gh search code --owner YOUR-ORG --filename settings.local.json
# The same search in the GitHub web search box
# org:YOUR-ORG path:.claude/settings.local.json
# 2. Was it ever committed, on any branch?
git log --all --oneline -- .claude/settings.local.json .claude/settings.json
# 3. List what you have approved with "don't ask again"
jq -r '.permissions.allow[]' .claude/settings.local.json
# 4. Grep the folder and its history for the usual suspects
grep -rEn 'PGPASSWORD=|sshpass -p|mysql -p|AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{20,}' .claude/
git log --all -p -- .claude | grep -E 'PGPASSWORD=|sshpass -p|mysql -p|AKIA[0-9A-Z]{16}'모두 표준 git, jq, grep 명령이지만 출력은 판결이 아니라 단서로 봐야 합니다. GitHub 코드 검색은 지금 브랜치에 있는 내용만 보기 때문에 2단계가 필요합니다.
스캐너로는 Apiiro가 쓴 두 가지인 Gitleaks와 TruffleHog가 있습니다. 히스토리에 대해 실행한 뒤 커스텀 규칙을 추가하세요. 기본 규칙은 키는 잡아도 플래그 뒤에 붙은 비밀번호는 못 잡기 때문입니다.
gitleaks git --redact -v .
trufflehog git file://.# .gitleaks.toml
[extend]
useDefault = true
[[rules]]
id = "password-inside-command"
description = "Password passed on a command line"
regex = '''(PGPASSWORD=|sshpass -p |mysql -p)\S+'''이 커스텀 규칙은 충분히 값어치를 합니다. Apiiro가 찾은 모든 파일에 두 도구를 돌려보니, 시크릿이 든 1,122개 파일 중 gitleaks는 564개, TruffleHog는 643개를 탐지했고, 215개는 둘 다 놓쳤습니다. 대부분 PGPASSWORD=, sshpass -p, mysql -p 뒤에 입력된 비밀번호였습니다(The Hacker News).
Apiiro는 보안팀에 .claude/, .cursor/, .gemini/, .specstory/와 에이전트 메모리 파일도 .env처럼 시크릿이 담긴 파일로 취급하라고 권고합니다. 저희도 팀에 설치된 모든 에이전트에 대해 같은 검색을 해보길 권합니다. Cursor, GitHub Copilot, Codex가 저장한 대화 기록에도 붙여 넣은 키가 들어 있을 수 있습니다.
승인 클릭 한 번이 비밀번호를 레포에 올리는 과정
Claude Code는 대부분의 셸 명령을 실행하기 전에 먼저 묻습니다. "Yes, and don't ask again"을 선택하면 .claude/settings.local.json에 허용 규칙이 기록됩니다. Anthropic 문서에 따르면 이렇게 한 Bash 승인은 "레포지토리와 명령 단위로 영구적으로" 유지됩니다(Claude Code docs). 문제는 규칙의 형태입니다. npm test * 같은 패턴일 수도 있고 명령어 전체일 수도 있는데, 명령어에 비밀번호가 들어 있으면 그 비밀번호가 평문으로 저장됩니다.

이 파일은 로컬에만 머물게 되어 있습니다. Anthropic 설정 문서에 따르면, 아직 이 파일을 무시하지 않는 레포에서 Claude Code가 파일을 처음 만들 때 **/.claude/settings.local.json을 전역 git excludes에 추가하며, 직접 만든 파일은 본인이 .gitignore에 한 줄을 넣어야 합니다(Claude Code docs). 이는 컴퓨터 한 대만 보호할 뿐, 새로 클론한 레포나 직접 만든 파일, 무시 규칙이 생기기 전에 커밋된 파일은 보호하지 못합니다.
Apiiro가 찾은 시크릿의 3분의 1 이상은 데이터베이스에 바로 접속할 수 있는 것이었고, 여기에는 데이터베이스 비밀번호 379개가 포함됩니다. 나머지에는 공개 서버용 SSH 로그인 43개, GitHub·GitLab·npm 토큰 42개, AWS 키 23개가 있습니다. 영향받은 파일의 소유 조직은 63곳이었고, 시크릿이 있는 레포의 절반에서는 파일이 최소 217일 동안 방치되어 있었습니다. Apiiro는 이것들이 아직 유효한지는 테스트하지 않았지만, 통보를 받은 한 회사는 자사 키가 실제로 살아 있었다고 확인해 주었습니다.
Anthropic의 지금까지 답변은 Hacker News 댓글 하나
2025년에 접수된 버그 리포트는 60일간 활동이 없다는 이유로 자동화 봇이 "not planned"로 닫았고, Apiiro 연구진은 자신들이 인용한 관련 리포트 중 Anthropic의 답변을 받은 것은 없다고 말합니다(The Hacker News). 공개적인 답변은 Hacker News에서 나왔는데, "Claude Code 팀의 Boris"라고 소개한 댓글 작성자였습니다. 그는 "지금까지 Claude Code는 시크릿 스크러빙을 해오지 않았다"고 쓰면서, 팀이 "이를 막기 위해 할 수 있는 일을 살펴보고 있다"고 했고, 이번 사례에서는 "파일이 수동으로 만들어져 체크인된 것"이라고 설명했습니다. 그리고 "권한 규칙은 구식입니다. 모두가 대신 auto mode를 써야 합니다"라고 덧붙였습니다.
수동 생성이라는 설명은 Apiiro의 데이터와 잘 맞지 않습니다. 추적한 레포지토리 1,105개 중 539개에서 Claude를 공동 작성자(co-author)로 표기한 커밋이 이 파일을 변경했습니다. 공동 작성자 표기가 git을 누가 실행했는지를 증명하지는 않지만, 누군가 손으로 만든 파일이라는 설명과는 맞추기 어렵습니다. 저희는 이 커밋 데이터가 댓글보다 반박하기 어렵다고 보며, Anthropic이 다른 입장을 내놓기 전까지는 Claude Code가 이 파일을 커밋할 수 있다고 전제하고 대응할 것입니다.
Grok Build는 서로 다른 방식으로 두 번 유출했습니다
Grok Build 관련 이야기 두 건이 뒤섞여 전해지고 있는데, 해결책이 서로 다릅니다. (보도에서는 이 회사를 SpaceXSI 또는 SpaceXAI라고 부릅니다.)
첫 번째는 2026년 초에 있었습니다. cereblab이라는 이름으로 글을 올리는 연구자가 Grok Build 0.2.93을 분석해, 커밋 히스토리와 커밋된 시크릿, API 키를 포함한 추적 중인 Git 레포지토리 전체를 클라우드 스토리지로 업로드한다고 보고했습니다(The Next Web). 이 분석에 따르면 업로드 규모는 작업에 필요한 양의 약 27,800배였고, 프라이버시 토글은 아무 효과가 없었다고 합니다. xAI는 이 도구를 "세션 중 코드베이스의 어떤 내용도 xAI 서버로 전송되지 않는다"고 홍보해 왔습니다. Elon Musk는 전송 사실을 인정하며 기존 사용자 데이터를 삭제하겠다고 밝혔습니다. TNW는 삭제를 확인한 독립 감사는 아직 없다고 덧붙입니다.
두 번째는 지금 뉴스에 오르내리는 건으로, 레포지토리와는 아무 관련이 없습니다. 보안 업체 Claroc은 Grok Build의 공유 링크를 받은 적 없는 사람들이 찾아낼 수 있다는 것을 발견했습니다(Claroc). Engadget에 따르면 각 링크는 최대 38비트 엔트로피의 무작위 단어 네 개로 이루어진 문구를 "도메인 왼쪽에" 붙이는 방식이었습니다(Engadget). 즉 호스트명에 들어간다는 뜻이고, Claroc은 passive DNS 서비스가 이런 조회 기록을 수집한다고 설명합니다. 공유된 ChatGPT와 Gemini 대화는 비밀 값을 URL 경로에 두기 때문에 DNS에는 보이지 않습니다. Claroc은 이렇게 씁니다. "누구도 추측하지 못하겠지만, 추측할 필요도 없습니다. 데이터셋에 목록이 있으니까요."
노출된 앱에는 실제로 중요한 자료가 들어 있었습니다. Claroc이 꼽은 사례로는 전략 고객 594곳의 영업 구역 지도, X 광고 제안서 8건, 실제 광고주 계정 보드 4개, 3,500명이 넘는 직원 명단이 담긴 병원 그룹의 직원용 앱, 소방관 개개인의 이름과 배지 번호가 나오는 소방서의 실시간 근무 보드가 있습니다. 테스트한 주소 중 94.7%는 로그인 없이 열렸습니다. Claroc은 앱의 약 2%에 높음 또는 치명적 등급을 받을 만큼 심각한 자료가 있었다고 추정합니다.
Claroc에 따르면 SpaceXSI는 자사 직원이 만든 앱 24개를 내렸지만 "다른 Grok 사용자와 조직의 앱은 내리지 않았습니다." Engadget은 Claroc이 X에서 Musk와 다른 회사 임원을 태그하고 나서야 회사가 대응했다고 전합니다. Claroc의 글에는 SpaceXSI가 기자의 질문에는 Grok 앱이 제작자가 공유하기로 선택하기 전까지는 비공개라고 답했지만, 보고서 자체에는 답하지 않았다고 나와 있습니다. 나머지 앱도 내리겠다는 성명은 찾지 못했습니다.
사용자 입장의 해결책은 단순합니다. Grok Build로 만들거나 공유한 것은 모두 공개된 것으로 간주하고, 필요 없는 링크는 내리고, 공유한 앱에 닿았던 자격 증명은 모두 교체하세요. 이 경우에는 .gitignore 한 줄로 해결되지 않습니다.
탈취된 키는 몇 분 안에 되팔립니다
Palo Alto Networks의 Unit 42는 탈취한 AI API 키가 프런티어 모델 접근권을 할인해 파는 암시장 "트랜스퍼 스테이션"을 통해 재판매되는 "토큰 재킹(token jacking)"을 설명합니다(Unit 42). 키의 유출 경로로는 노출된 코드 레포지토리, 인포스틸러, 악성 npm 패키지가 꼽힙니다. 한 사례에서는 공격자가 노출된 자격 증명을 몇 분 만에 트랜스퍼 스테이션에 통합했고, 발견되기 전까지 "100만 달러에 가까운 요금"이 청구되었습니다. Unit 42는 피해자가 "자금을 회수할 방법이 거의 없다"고 말합니다. 권장하는 방어책은 평범합니다. 알림이 있는 지출 한도, 장기 키 대신 단기 토큰, 한도를 조정할 수 있는 모든 권한 계정에 대한 검토입니다.
유출 조치: 무시하고, 추적을 끊고, 교체하세요
먼저 교체하고, 정리는 그다음입니다. 폐기한 키는 모든 포크와 캐시된 사본에서도 쓸모가 없지만, 최신 커밋에서 지우기만 한 키는 히스토리에서 여전히 살아 있습니다. GitHub는 노출된 자격 증명을 즉시 교체하라고 하며, 히스토리를 지우는 일은 "자격 증명을 이미 폐기했다면 시간이 많이 들고 불필요한 경우가 많다"고 말합니다(GitHub docs).
# Rotate the exposed credentials first (table below), then:
# Stop tracking the local file (keeps your copy on disk)
git rm --cached .claude/settings.local.json
# Add to the repo's OWN .gitignore, not just your global excludes
printf '%s\n' '.claude/settings.local.json' '.specstory/' >> .gitignore
git add .gitignore
git commit -m "Stop tracking agent local settings"
# Drop any allow rule that looks like it holds a secret, even if never committed
jq '.permissions.allow |= map(select(test("PGPASSWORD|password|token|secret|key"; "i") | not))' \
.claude/settings.local.json > .claude/settings.local.json.new \
&& mv .claude/settings.local.json.new .claude/settings.local.json.cursor/나 .gemini/를 통째로 무시하기 전에는 한 번 생각해 보세요. 일부 팀은 공유 규칙을 일부러 그곳에 커밋합니다.
주요 제공업체의 키 교체 방법
모든 제공업체가 콘솔에 이를 위한 버튼을 두고 있으며, 안전한 순서는 새 키 생성, 배포, 그다음 기존 키 폐기입니다. 먼저 삭제하면 프로덕션이 멈출 수 있습니다.
| 제공업체 | 교체 방법 | 참고 |
|---|---|---|
| AWS | 두 번째 IAM 액세스 키를 만들고, 앱을 업데이트하고, 마지막 사용 시점을 확인한 뒤, 기존 키를 비활성화하고 삭제 | aws iam create-access-key, get-access-key-last-used, update-access-key --status Inactive, delete-access-key (AWS docs) |
| GitHub | 토큰을 삭제하고 만료일을 지정해 새로 생성 | 공개 레포지토리나 gist에 푸시된 토큰은 GitHub가 자동으로 폐기하며, 그 밖의 곳에서 유출된 경우 REST API로 폐기 요청을 제출할 수 있음 (GitHub docs) |
| Stripe | 대시보드에서 키를 롤(roll)하고, 앞으로는 제한된 키(restricted key)를 사용 | 누가 봤는지 확실하지 않아도 교체할 것. 탐지된 키는 Stripe가 비활성화할 수 있음 (Stripe docs) |
| OpenAI | 대체 키를 만들고, 앱을 업데이트하고, 정상 작동을 확인한 뒤 기존 키를 폐기 | 프로젝트 키에 만료 기한을 설정하고 앱에는 프로젝트 서비스 계정을 사용 (OpenAI docs) |
Anthropic과 xAI를 포함해 표에 없는 제공업체는 교체 절차를 확인하지 못했으니 해당 업체의 문서를 따르세요. Apiiro가 찾은 대부분을 차지하는 데이터베이스 비밀번호와 SSH 로그인은 비밀번호를 바꾸고, 열려 있는 세션을 종료한 뒤, 파일이 처음 커밋된 날부터의 접근 로그를 확인하세요.
GitHub 스캐너를 켜고 한계를 파악하세요
Secret scanning은 모든 브랜치의 전체 히스토리와 이슈, 풀 리퀘스트, 디스커션, 위키를 검사합니다. 공개 레포지토리에서는 무료로 자동 적용되며, 조직의 비공개·내부 레포에서는 GitHub Secret Protection이 필요합니다(GitHub docs). 파트너사의 키 형식이 탐지되면 GitHub가 해당 제공업체에 알리고, 제공업체는 내 레포지토리에 아무 알림 없이 키를 폐기할 수도 있습니다.
Push protection은 이런 파일 중 상당수가 공개되기 전에 막았을 수 있는 계층입니다. 탐지된 시크릿이 포함된 푸시를 차단합니다. GitHub 문서에 따르면 사용자 수준 설정은 GitHub.com의 공개 레포지토리로 푸시할 때 기본으로 켜져 있고, 레포지토리 수준 설정은 기본으로 꺼져 있어 레포 관리자, 조직 소유자 또는 보안 관리자가 켜야 합니다(GitHub docs). 제공업체 패턴, 개인 키와 연결 문자열 같은 범용 패턴, 직접 만든 커스텀 패턴, 그리고 비밀번호 같은 비정형 시크릿을 위한 AI 탐지 범주(퍼블릭 프리뷰)를 검사합니다. 마지막 범주는 Apiiro가 찾아낸 빈틈을 겨냥한 것으로 보입니다. REST API 푸시에는 적용되지 않고, 명령줄 푸시와 웹 UI 커밋, 파일 업로드에는 적용됩니다.
우회 수단도 알아두세요. 기본적으로 쓰기 권한이 있는 사람은 누구나 "나중에 고치겠다" 같은 사유를 골라 차단을 우회할 수 있고, 그러면 알림이 생성되고 소유자에게 이메일이 갑니다. 에이전트가 내 대신 커밋한다면 지정된 사람만 시크릿을 통과시킬 수 있도록 delegated bypass를 설정하세요.
오늘 바꿔야 할 에이전트 권한 설정
세 가지 습관이 있었다면 비밀번호가 파일에 들어가지 않았을 겁니다. 자격 증명이 든 명령어 자체가 아니라 패턴을 승인하세요. 시크릿은 환경 변수에 넣어, 명령어가 값이 아닌 이름만 담게 하세요. 그리고 애초에 시크릿이 든 파일에는 에이전트의 접근을 거부하세요. Anthropic 설정 문서에 나온 형태는 다음과 같습니다.
{
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test *)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)"
]
}
}에이전트가 실행해야 할 명령은 psql "$DATABASE_URL" 같은 형태이므로, 승인 규칙에는 변수 이름만 저장되고 다른 것은 저장되지 않습니다. 변수는 에이전트가 읽을 수 있는 파일이 아니라 시크릿 매니저나 셸 프로필에서 불러오세요.
팀에 중요한 문서상의 세부 사항이 두 가지 있습니다. 커밋된 .claude/settings.json의 allow 규칙은 각 팀원이 해당 폴더를 신뢰할 때까지 적용되지 않는 반면 deny와 ask 규칙은 즉시 적용됩니다. 또 auto와 bypassPermissions 모드는 프로젝트나 로컬 설정으로는 적용되지 않습니다. 조직은 allowManagedPermissionRulesOnly로 allow 규칙을 잠글 수 있습니다. 앞서 인용한 Claude Code 팀원은 auto mode를 쓰면 권한 규칙이 필요 없다고 말합니다. 그래도 저희는 .env deny 규칙을 유지할 것입니다. 두 줄이면 되고, 파일이 커밋되는 순간부터 적용되니까요.
다른 도구는 설정 이름이 다르지만 질문은 같습니다. 도구가 승인 기록, 히스토리, 대화 기록을 어디에 저장하며, 그 위치가 레포 안인가 하는 것입니다. Apiiro는 문서를 기준으로 비교한 코딩 에이전트 16개 중 승인된 명령어 전체를 기본으로 프로젝트 파일에 저장하는 것이 확인된 것은 Claude Code뿐이라고 밝혔습니다. 나머지 15개도 대화 기록, 붙여 넣은 키, 메모리 파일을 통해 유출될 수 있습니다. 각 도구가 무엇을 저장하는지는 터미널 코딩 에이전트 비교와 Cursor vs Copilot vs Windsurf 글에서 다룹니다.
가장 강력한 통제는 프롬프트에 의존하지 않습니다. 에이전트를 컨테이너나 샌드박스에서 실행하고, 해당 작업에 필요한 자격 증명만 제한된 범위와 짧은 수명으로 주세요. 구체적인 방법은 How to Contain an AI Agent에 정리했습니다.
교체는 사용자의 몫, 기본값은 벤더의 몫입니다
명령어에 비밀번호를 입력한 것은 사용자의 실수이고, 교체도 사용자의 몫입니다. 하지만 전체 명령어를 프로젝트 파일에 저장해 놓고, 그것을 비공개로 유지하는 일을 홈 디렉터리의 exclude에 맡기는 도구는 노트북 한 대에서만 작동하는 안전장치를 가진 셈입니다.

기본값이 곧 정책이고, 이번에는 기본값이 결과를 갈랐습니다. 규칙을 저장하기 전에 시크릿을 지우거나 무시 설정을 레포 자체의 .gitignore에 써넣는 Claude Code였다면 근원에서 구멍을 막았을 것입니다. Anthropic은 이를 검토 중이라고 하지만(저희는 일정을 알고 싶습니다), 비활성 봇이 닫아버린 버그 리포트는 믿음을 주지 못하고, 커밋 데이터도 "수동 생성"이라는 설명과 맞지 않습니다.
공유 링크 사건에서는 Grok Build가 더 심각한 경우인데, 사용자가 잘못한 것이 없기 때문입니다. passive DNS로 누구나 찾을 수 있는 링크는 공유 메뉴가 어떻게 안내했든 비공개가 아닙니다. 게다가 앞선 업로드 건은 정반대로 말하던 마케팅 문구와 모순되었습니다. 저희는 공유 링크 문제가 고쳐지고 외부 감사가 삭제를 확인하기 전까지는 Grok Build에 고객 목록이나 영업 구역 지도, 프로덕션 자격 증명을 넣지 않을 것입니다. 상황이 달라지면 저희 의견도 달라질 것입니다.
에이전트 폴더를 .env 파일처럼 취급하고, 위 설정에 오후 한나절을 쓰세요. 도구 자체는 AI 코딩 어시스턴트 보드에서, 에코시스템의 보안 측면은 AI 사이버 보안 도구 보드에서 비교해 보실 수 있습니다.
팀 전체를 위한 체크리스트
오늘 해당하는 항목에 체크하면 점수로 어디서부터 시작할지 알 수 있습니다. 2점짜리 항목은 저희라면 점심 전에 끝낼 일입니다.
자주 묻는 질문
.claude/settings.local.json은 커밋해도 안전한가요?
아니요. 이 파일에는 개인 승인 기록이 담겨 있고 자격 증명이 들어 있을 수도 있습니다. Anthropic 문서에 따르면 Claude Code는 파일을 만들 때 전역 exclude를 통해 git에서 제외하지만, 직접 만든 사본은 본인이 무시 규칙을 추가해야 합니다. 각 레포의 .gitignore에 추가하고, 이미 커밋된 적이 있다면 git rm --cached로 추적을 끊으세요.
레포가 비공개여도 키를 교체해야 하나요?
네, 파일에 자격 증명이 들어간 적이 있다면 교체해야 합니다. 비공개 레포도 노트북과 CI 러너에 클론되고, 다른 계정으로 포크되며, 가끔은 공개로 전환됩니다. 조직의 비공개 레포에 대한 GitHub secret scanning은 유료 플랜이 필요하므로, 자동 점검이 전혀 없었을 수도 있습니다.
레포에서 파일을 삭제하면 시크릿도 사라지나요?
최신 커밋에서만 사라지고 그 외에는 그대로입니다. 히스토리와 포크, 캐시에는 이전 버전이 남아 있으며, Apiiro는 이 파일의 이전 버전에만 나타나는 시크릿 734개를 찾았습니다. 먼저 자격 증명을 교체하고, 히스토리 재작성은 레포를 깔끔하게 정리하고 싶을 때만 하세요.
GitHub Copilot, Cursor, Codex도 같은 문제가 있나요?
Apiiro는 비교한 에이전트 16개 중 승인된 명령어 전체를 기본으로 프로젝트 파일에 저장하는 동작을 Claude Code에서만 확인했습니다. 그렇다고 다른 도구가 문제없다는 뜻은 아닙니다. 작업 디렉터리에 대화 기록이나 메모리를 쓰는 에이전트라면 어디든 같은 무시 규칙이 필요합니다.