2026년 11월 11일
AI가 PC 곳곳에 API 키를 남긴다?
AI와 일하는 법

AI가 PC 곳곳에 API 키를 남긴다?

Caston 2026년 10월 8일 1 min read

AI 코딩 도구를 본격적으로 쓰기 시작하면서부터, 코드 생성 속도와 검토 속도 사이 간격이 눈에 띄게 벌어졌다. 만들어진 코드가 돌아가니까 일단 붙여넣고, 이것저것 덧붙이다 보면 어느새 커밋이 쌓인다. 그 사이클이 빠를수록 한 번 쓱 훑어보는 검토 시간이 짧아지고, 세부 사항은 뒤로 밀린다. 한동안 그렇게 했으니 뭔가 박혀 있지 않을까 싶어, 블로그 파이프라인 저장소에 스캐너를 돌려봤다.

키가 심기는 경로

AI 도구가 만들어주는 코드는 일단 동작부터 하게 설계된다. 자격 증명을 환경 변수로 빼는 습관은 코드를 받아쓰는 사람이 따로 챙겨야 한다. 그런데 속도가 빨라질수록 그 챙기는 단계가 줄어든다. “이 API 호출 예시 코드 짜줘”라는 요청에 AI가 응답할 때, Authorization 헤더나 Bearer 토큰 자리에 실제처럼 생긴 문자열을 그냥 넣어버리는 경우가 흔하다. 결국 API 키가 코드 안에 그냥 박힌 채 커밋된다.

더 실질적인 문제는 이력이다. 나중에 .env 파일로 옮기고 .gitignore에 추가했다고 해도, 처음 하드코딩한 시점의 커밋은 저장소 이력에 그대로 남는다. 저장소를 클론하면 그 이력도 딸려온다. 공개 저장소라면 누구든 볼 수 있고, 비공개라도 접근 권한이 있는 사람이라면 열어볼 수 있다. GitHub 검색 봇이나 자동화된 스캐너가 24시간 이내에 공개 커밋을 인덱싱한다는 보고도 있어, 잠깐 올렸다 지워도 이미 늦을 수 있다.

GitHub은 시크릿 스캐닝을 자체적으로 제공한다. 시크릿 스캐닝이란 저장소에 올라온 코드에서 알려진 형식의 키나 토큰을 자동으로 감지하는 기능이다. GitHub 시크릿 스캐닝은 공개 저장소와 Advanced Security 플랜 구독자 위주로 작동한다. 비공개 저장소의 커밋 이력 전체를 빠짐없이 커버하지는 않는다. 스스로 검색하는 단계를 거칠 이유가 여기서 생긴다.

AI 도구가 키를 심는 패턴은 크게 세 가지다. 예시 코드를 생성할 때 placeholder 자리에 실제처럼 보이는 값을 넣는 경우가 하나다. 테스트 스크립트에서 환경 변수 대신 리터럴 문자열을 쓰는 경우가 또 하나다. “일단 돌아가게만 해줘”라는 요청에 빠르게 키를 박아 넣는 경우가 마지막이다. 셋 다 검토 없이 그냥 쓰면 커밋으로 이어진다.

검색 방법

현재 파일 상태만 보면 안 된다는 게 핵심이다. 파일을 지우거나 내용을 바꿔도, 이전 커밋에 해당 값이 있으면 이력에서 꺼낼 수 있다. git 자체 명령으로도 이력을 뒤질 수 있다. git log -p --all -S "sk-" 같은 명령을 실행하면 해당 문자열이 등장하거나 사라진 커밋을 전부 나열한다. OpenAI API 키의 경우 sk-, AWS 액세스 키는 AKIA처럼 서비스마다 고유한 접두어가 있어 이를 기준으로 검색하면 직접 눈으로 확인하기 좋다.

더 체계적인 방법은 전용 스캐너를 쓰는 것이다. gitleaks는 저장소 커밋 이력 전체를 스캔해서 알려진 형식의 시크릿을 찾아주는 오픈소스 도구다. gitleaks는 설치 후 gitleaks detect --source . 한 줄로 현재 저장소를 검사한다. 결과를 JSON으로도 받을 수 있어서 자동화 파이프라인에 연결하기 좋다. 커밋 해시, 파일 경로, 줄 번호, 감지된 규칙 이름까지 함께 출력되기 때문에 어디를 고쳐야 할지 바로 특정할 수 있다.

trufflehog는 다른 접근법을 쓴다. 단순히 패턴을 매칭하는 것에 그치지 않고, 찾아낸 값이 실제 유효한 키인지 API를 통해 확인한다. trufflehog는 AWS, GitHub, Stripe를 포함해 수백 개 서비스의 키 형식을 인식한다. 활성 상태인지 폐기된 상태인지 구별해 준다는 점이 gitleaks와의 차이다. 이미 쓸 수 없는 키와 지금 당장 위험한 키를 따로 볼 수 있다.

두 도구를 병행하는 게 실용적이다. gitleaks는 설정이 단순하고 속도가 빠르다. trufflehog는 false positive를 걸러내고 실제 위험 수준을 가려내는 데 낫다. 로컬에서 먼저 돌려보고 결과를 확인한 다음, CI에 붙이는 순서가 일반적이다. 둘 다 무료 오픈소스라서 일단 써보는 데 비용이 들지 않는다.

검출 결과

커밋 이력 전체를 훑었다. 나온 건 1건이다. 규칙 이름은 discord-client-id, 파일은 config/env.redacted.

이름 그대로 비밀값을 지운 복구본이다. 8월에 .env를 날려먹고 다시 만들면서, 봇 토큰과 API 키 자리에 REDACTED 라고만 적어 비워둔 파일이다. 스캐너가 잡은 건 그 파일에 남아 있던 Discord ID 숫자였다. 사용자 ID와 채널 ID가 들어 있는데, 둘 다 열여덟 자리 안팎이라 토큰과 형식이 비슷하다.

Discord ID는 자격 증명이 아니다. 같은 서버에 있는 사람이면 누구나 볼 수 있는 식별자고, 그것만으로는 아무것도 할 수 없다. 자릿수가 비슷해서 패턴에 걸렸을 뿐이다. 진짜 유출은 0건, 오탐이 1건이었다.

그렇다고 이 저장소에 비밀값 사고가 없었느냐 하면 아니다. 8월에 .env가 통째로 사라져서 봇 배달이 멈춘 적이 있고, 9월에는 인증 토큰이 서비스 설정을 출력하다가 화면에 그대로 찍힌 적이 있다. 둘 다 스캐너가 못 잡는 종류다. 앞엣것은 커밋이 아니라 파일이 사라진 일이고, 뒤엣것은 토큰이 .bashrc와 systemd 설정에 있었다. 저장소 바깥이다.

스캐너는 저장소 안에 커밋된 패턴만 본다. 0건이 나왔다고 안전한 게 아니라, 스캔이 보는 범위가 거기까지라는 뜻이다.

예상 못 한 자리에서 나오는 것도 있다. config 파일 안에 기본값으로 들어간 키, README의 사용 예시에 실수로 넣은 실제 토큰 같은 것들이다. 커밋 메시지 자체에 적어둔 값도 나온다. 커밋 메시지는 특히 맹점이 되기 쉽다. 파일이 아니라서 .gitignore가 아무런 역할을 못 한다.

AI 생성 코드에서 유독 자주 보이는 패턴도 있다. “아래 키로 테스트해봐”라고 요청했을 때 AI가 그 키를 예시 코드 안에 넣고, 사용자가 그걸 그대로 커밋하는 경우다. AI는 자격 증명을 환경 변수로 분리하라고 조언하기도 하지만, 정작 코드 자체에서는 리터럴로 써넣는 경우가 많다. 조언과 생성물이 따로 논다. 이 간극은 AI가 나쁜 의도를 가져서가 아니라, 동작하는 예시를 만드는 것과 보안 관행을 지키는 것이 AI 입장에서는 별개의 목표이기 때문이다.

알고 나면 불안이 달라진다. 막연하게 “어딘가 문제가 있을 수도 있겠다”가 아니라, 정확히 어느 커밋, 어떤 파일에 뭐가 있는지 볼 수 있게 된다. 그 쪽이 훨씬 낫다. 스캔 결과를 손에 쥐고 나면, 우선순위가 생기고 처리 순서도 명확해진다. 모르는 채로 두는 것보다 찾아낸 뒤 처리하는 게 통제감이 있다.

처리 순서

키가 이력에 있다는 사실을 확인하면, 첫 번째로 해야 할 일은 해당 키를 즉시 폐기하는 것이다. 이력을 지우는 작업보다 키 폐기가 먼저다. 이력 정리에 시간이 걸리는 동안에도 키가 살아 있으면 그 사이가 위험하다. 몇 시간, 심지어 몇 분 사이에 자동화된 스캐너가 이미 그 키를 발견하고 악용 시도가 이뤄질 수 있다. 순서를 바꾸면 안 된다.

키 폐기는 해당 서비스의 대시보드에서 직접 한다. AWS라면 IAM 콘솔에서 해당 액세스 키를 비활성화하고 새 키를 발급한다. Stripe, OpenAI, GitHub 토큰도 각 서비스 설정 페이지에서 바로 처리할 수 있다. 재발급한 키는 즉시 .env 파일이나 시크릿 매니저에 저장한다. 코드에는 직접 쓰지 않는다.

이력 정리는 그 다음 단계다. BFG Repo Cleaner는 커밋 이력에서 특정 값을 제거해주는 도구로, git 내장 명령인 filter-branch보다 빠르고 쓰기 쉽다. 다만 이력을 재작성하면 기존 커밋 해시가 전부 바뀐다. 다른 팀원들이 클론한 복사본이 있다면 모두에게 알리고 재클론하도록 해야 한다. 혼자 쓰는 저장소라면 절차가 단순하다.

재발생을 막는 설정도 함께 해야 한다. .gitignore에 .env, *.pem, *_key.json 같은 패턴을 미리 추가해 두는 게 첫째다. 더 확실한 방법은 pre-commit hook에 gitleaks를 붙이는 것이다. pre-commit hook은 git commit 명령 실행 직전에 자동으로 돌아가는 스크립트다. 커밋 자체를 막는 방식이라 실수로 넘어갈 여지가 없다.

pre-commit 프레임워크를 쓰면 설정이 한결 간단하다. .pre-commit-config.yaml 파일에 gitleaks hook을 추가하고 pre-commit install을 실행하면 된다. 이후로는 시크릿이 포함된 파일을 커밋하려 할 때 자동으로 차단된다. 팀 저장소라면 이 설정 파일을 저장소에 포함해서 모든 기여자가 같은 hook을 쓰도록 하는 게 낫다. 한 번 설정해두면 그 이후로는 신경 쓸 일이 줄어든다.

Leave a Comment