GitHub Secret Scanning으로 유출된 비밀 정보 잡아내기

GitHub Secret Scanning으로 유출된 비밀 정보 잡아내기

소스 코드 저장소에 API 키나 토큰이 실수로 들어간 적, 한 번쯤 있으시죠? 당장 git rm으로 지우고 강제 푸시를 해도 깃 히스토리에는 흔적이 남고, 공개 저장소라면 봇이 몇 분 안에 그 키를 긁어가 버립니다. 악의적인 사용자가 발견하기 전에 깃허브가 먼저 찾아서 알려주면 좋겠다는 생각이 절로 들죠.

이번 글에서는 깃허브가 무료로 제공하는 Secret Scanning 기능이 어떻게 동작하고, 푸시 시점부터 사후 알림까지 어떤 방어선을 쌓아주는지 정리해 보겠습니다.

Secret Scanning이 푸는 문제

비밀 정보가 저장소로 새어 들어가는 경로는 꽤 여러 갈래입니다. .env 파일을 .gitignore에 빠뜨려서 통째로 커밋하기도 하고, 디버깅용으로 잠깐 하드코딩한 토큰을 그대로 두고 푸시해 버리기도 하죠. 한 번 저장소에 들어간 비밀은 강제 푸시로 지워도 다른 사람의 로컬 클론, 포크, 깃허브 캐시 어딘가에 살아남습니다.

그래서 비밀이 새어 나갔을 때 가장 확실한 대응은 “지우는 것”이 아니라 “무효화(rotate)하는 것”입니다. 유출된 토큰을 폐기하고 새로운 토큰을 발급받아야 진짜로 안전해지는 거죠. 문제는 자신이 비밀을 흘렸다는 사실 자체를 모르고 지나가는 경우가 너무 많다는 점입니다.

Secret Scanning은 이 사각지대를 메우기 위한 기능입니다. 깃허브가 저장소에 푸시되거나 이미 들어가 있는 코드에서 알려진 형태의 비밀 정보를 찾아내고, 발견 즉시 저장소 관리자와 토큰 발급자 양쪽에 알려줍니다.

작동 방식 한눈에 보기

Secret Scanning은 크게 두 갈래로 동작합니다.

첫째는 저장소 안의 모든 깃 히스토리, 이슈, PR 본문, 코멘트, 위키, 그리고 패키지 메타데이터까지 훑는 정적 스캔입니다. 한 번 활성화하면 과거 커밋까지 거슬러 올라가서 비밀처럼 생긴 문자열을 모두 찾아내요. 둘째는 푸시되는 순간 차단하는 Push Protection입니다. 개발자의 로컬에서 푸시가 올라오는 시점에 정규식과 검증 로직으로 비밀을 감지해서, 아예 깃허브 서버에 도달하지 못하도록 막아버리는 방식이죠.

탐지 대상은 깃허브가 자체적으로 정의한 패턴과, 외부 서비스 제공자들이 등록한 패턴 두 가지로 나뉩니다. AWS, Stripe, Slack, OpenAI 같은 업체들이 자사 토큰의 구조를 깃허브에 등록해두면, 깃허브는 그 패턴이 발견됐을 때 토큰 발급사에 직접 알려줍니다. 그러면 발급사가 해당 토큰을 자동으로 폐기하거나 사용자에게 알림을 보내주죠. 이 과정을 깃허브는 Secret Scanning Partner Program이라고 부릅니다.

Secret Scanning이 잡아내는 흐름
개발자 푸시

    ▼ Push Protection (선택적 차단)
깃허브 서버

    ▼ 저장소 스캔 (커밋, 이슈, PR, 위키)
비밀 발견

    ├─→ 저장소 관리자에게 알림
    └─→ 토큰 발급사에게 알림 → 자동 폐기

Push Protection으로 사전에 막기

Push Protection은 비밀이 저장소에 도달하기 전에 차단하는 가장 강력한 방어선입니다. 공개 저장소든 비공개 저장소든 무료로 활성화할 수 있고, 정확도가 높은(high-confidence) 패턴만 검사하기 때문에 거짓 양성이 거의 없습니다.

푸시가 차단되면 개발자에게는 다음과 같은 메시지가 표시됩니다.

푸시 차단 메시지
remote: error: GH013: Repository rule violations found for refs/heads/main.
remote:
remote: - GITHUB PUSH PROTECTION
remote:   —————————————————————————————————————————
remote:     Resolve the following violations before pushing again
remote:
remote:     - Push cannot contain secrets
remote:
remote:     —— OpenAI API Key ————————————————————————————————————
remote:      locations:
remote:        - commit: a1b2c3d4
remote:          path: src/config.js:14

대부분은 여기서 멈추고 토큰을 코드에서 제거한 뒤 다시 커밋하면 됩니다. 하지만 가끔은 토큰처럼 보이지만 실제로는 테스트용 가짜 값이거나, 이미 무효화된 키를 의도적으로 남겨두는 경우도 있죠. 이때는 푸시를 우회할 수 있는데, 깃허브는 우회 사유를 반드시 선택하도록 강제합니다.

우회 옵션은 “테스트용 가짜 비밀이다”, “사용 중인 진짜 비밀이지만 그대로 두겠다”, “오탐지를 신고하겠다” 세 가지입니다. “진짜 비밀이지만 그대로 두겠다”를 선택하면 보안 알림이 즉시 생성되어 저장소 관리자에게 통보됩니다. 이 강제 흐름이 중요한 이유는, 우회를 너무 쉽게 만들면 결국 모두가 무심코 우회 버튼을 누르게 되기 때문이에요.

알림과 자동 폐기 흐름

Push Protection이 뚫렸거나, 기능을 활성화하기 전부터 이미 비밀이 들어가 있던 저장소라면 사후 스캔이 작동합니다. 깃허브는 저장소의 모든 깃 히스토리를 처음부터 끝까지 훑어서 비밀로 의심되는 문자열을 찾아내고, 일치하는 패턴이 있으면 보안 알림(Security Alert)을 생성합니다.

알림은 저장소의 Security 탭 아래 Secret scanning 메뉴에서 확인할 수 있습니다.

알림 페이지 URL
https://github.com/<사용자>/<저장소>/security/secret-scanning

각 알림에는 발견된 비밀의 종류, 위치(파일 경로와 줄 번호), 첫 발견 시점이 함께 표시됩니다. 알림을 받은 관리자는 곧바로 토큰을 폐기하고 새로 발급받아야 합니다.

여기서 깃허브가 한 발 더 나아가는 부분이 있는데요. 파트너 프로그램에 등록된 서비스의 토큰이 발견되면, 깃허브는 발견 사실을 토큰 발급사에 자동으로 알려줍니다. 예를 들어 AWS Access Key가 공개 저장소에 노출되면 깃허브가 AWS에 통보하고, AWS는 해당 키를 즉시 격리하거나 폐기 처리하는 식이죠. 사용자가 손쓸 새도 없이 토큰이 무력화되니, 유출된 키로 인한 피해 범위가 극적으로 줄어듭니다.

활성화 방법

공개 저장소(public repository)에서는 Secret Scanning과 Push Protection이 별도 설정 없이 기본으로 켜져 있습니다. 2024년부터 깃허브가 모든 공개 저장소에 자동 적용했기 때문이죠.

비공개 저장소나 조직(organization) 저장소에서는 직접 활성화해야 합니다. 저장소의 Settings 탭에서 Code security 메뉴로 들어가면 Secret scanning 섹션이 보입니다.

설정 페이지 URL
https://github.com/<사용자>/<저장소>/settings/security_analysis

여기서 Secret Scanning과 Push Protection을 각각 활성화할 수 있습니다. 조직 단위로는 비공개 저장소까지 일괄 적용하려면 GitHub Advanced Security 라이선스가 필요했는데, 최근에는 Secret Scanning 기능만 묶은 별도 상품도 분리되어 도입 비용이 한결 가벼워졌어요.

조직 전체에 일관된 정책을 적용하고 싶다면 organization-level의 보안 설정에서 일괄 활성화할 수도 있습니다. 새로 만들어지는 저장소에 자동으로 켜지도록 기본값을 잡아두면, 개별 저장소마다 설정을 챙기지 않아도 되니 편리합니다.

커스텀 패턴 정의하기

깃허브가 기본으로 잡아내는 패턴은 잘 알려진 서비스의 토큰들입니다. 하지만 사내에서 자체적으로 발급하는 API 키나 데이터베이스 비밀번호 같은 형식은 깃허브가 자동으로 알지 못하죠. 이때 커스텀 패턴(custom pattern) 기능으로 직접 정규식을 등록할 수 있습니다.

예를 들어 사내 API 키가 INTERNAL_ 접두어와 32자리 16진수로 구성된다면 다음과 같이 패턴을 등록합니다.

정규식 예시
INTERNAL_[0-9a-f]{32}

깃허브는 이 정규식과 일치하는 문자열을 발견하면 일반 비밀과 동일한 흐름으로 알림을 만들고, Push Protection도 적용해줍니다. 패턴을 처음 등록하면 저장소 전체를 다시 스캔해서 과거 커밋까지 검사하므로, 이미 들어가 있던 사내 비밀도 함께 잡혀 나옵니다.

조직에서 자주 쓰는 형식이라면 organization-level에서 한 번만 등록해두면 모든 저장소에 동일하게 적용되니, 사내 비밀 정보 표준이 정해져 있다면 꼭 활용해보세요.

비밀이 유출되었을 때

알림을 받았다면 가장 먼저 할 일은 코드에서 비밀을 지우는 것이 아니라 토큰을 폐기하는 것입니다. 이미 깃 히스토리에 들어간 시점에서 그 비밀은 “유출된 것”으로 간주해야 하거든요.

폐기 순서는 대략 이렇게 진행하면 됩니다. 우선 발급사 콘솔에서 해당 토큰을 즉시 폐기하거나 무효화합니다. 그다음 새 토큰을 발급받아서 애플리케이션 환경 변수, 시크릿 매니저, CI/CD 설정 등 사용처를 모두 갱신합니다. 마지막으로 깃 히스토리에서 비밀을 제거하는 작업을 합니다. git filter-repo나 BFG Repo-Cleaner 같은 도구를 쓸 수 있지만, 협업 중인 저장소에서는 강제 푸시가 다른 팀원들의 로컬 저장소를 망가뜨리니 신중하게 진행해야 합니다.

비밀이 노출됐다고 해서 패닉할 필요는 없습니다. 중요한 건 발견 즉시 토큰을 폐기해서 공격자가 그 키로 할 수 있는 일이 없도록 만드는 것이고, 이 작업이 분 단위로 빠르게 이뤄지도록 평소에 절차를 만들어 두는 것이죠.

다른 보안 기능과의 조합

Secret Scanning은 단독으로도 강력하지만, 깃허브의 다른 보안 기능과 함께 쓰면 효과가 배가 됩니다.

Dependabot이 의존성에 숨어 있는 보안 취약점을 잡아준다면, Secret Scanning은 코드 안에 직접 들어간 비밀을 잡아냅니다. 공급망(supply chain) 공격과 자격 증명 유출이라는 두 축을 동시에 방어하는 셈이죠. 여기에 Claude Code Security 같은 AI 기반 코드 분석을 더하면 비즈니스 로직 결함이나 권한 검증 누락 같은 복잡한 취약점까지 함께 다룰 수 있습니다.

세 가지 도구의 역할이 다르다는 점을 이해하고 활용하면, 한정된 보안 인력으로도 상당한 수준의 방어 체계를 구축할 수 있어요.

마치며

지금까지 깃허브 Secret Scanning의 작동 방식과 Push Protection, 알림 흐름, 활성화 방법, 커스텀 패턴까지 살펴봤습니다. 한때 “Pro 플랜에서만 되는 비싼 기능”이었던 Secret Scanning은 이제 모든 공개 저장소에 무료로 적용되고, 비공개 저장소에서도 비교적 부담 없이 도입할 수 있게 되었습니다. 이 정도로 설정 비용이 낮은 보안 기능이라면 켜지 않을 이유가 없죠.

저장소를 운영하고 있다면 오늘 바로 설정 페이지에 들어가서 Push Protection까지 활성화해보시길 권합니다. 한 번의 클릭이 토큰 유출로 인한 사고와 그 뒷수습을 막아줄 수도 있으니까요.

더 자세한 내용은 About Secret Scanning 공식 문서를 참고하세요.

This work is licensed under CC BY 4.0 CC BY

개발자를 위한 뉴스레터

달레가 정리한 AI 개발 트렌드와 직접 만든 콘텐츠를 전해드립니다.

Discord