추가된 다섯 가지 탐지 유형부터 확인하자
개발 중인 앱을 GitHub에 올리면서 인증키까지 함께 올렸다면, 파일에서 그 한 줄을 지우는 것만으로는 해결되지 않는다. 코드의 복사본이나 과거 커밋에 값이 남을 수 있고, 이미 읽힌 키는 서비스 제공자가 사용을 막기 전까지 악용될 수 있기 때문이다. GitHub의 Secret scanning은 이런 키를 찾아 경고하는 기능이다. 10월 5일 공지는 Lovable·Pydantic·Supabase 관련 탐지 범위의 변화를 정리했다.
공지에 명시된 유형은 다섯 가지다. Lovable의 API 키 하나, Pydantic의 Logfire 토큰과 AI Gateway API 키 두 가지, Supabase의 OAuth 접근 토큰과 범위를 지정한 개인 접근 토큰 두 가지다. 서비스 이름이 같다는 이유로 그 서비스가 발급하는 모든 키 형식이 새로 지원된다고 읽으면 안 된다. 아래 표의 정확한 유형 이름이 이번 발표를 해석하는 기준이다.
발표 날짜에도 주의할 부분이 있다. 10월 5일 글은 Lovable을 새 파트너로 소개하지만, 8월 7일 공식 공지에도 같은 회사의 파트너 참여와 lovable_api_key 탐지가 이미 적혀 있다. 따라서 이 글에서는 다섯 유형을 10월 공지에 나열된 목록으로 소개하되, Lovable의 최초 지원일이 10월 5일이라고 단정하지 않는다. 두 공식 글의 표현이 겹치는 이유는 확인하지 못했다.
이 변화의 의미는 개발자가 다루는 인증 수단 중 탐지할 수 있는 형식이 넓어진다는 데 있다. 공지 자체는 짧지만 실제 대응에서는 어떤 키가 발견됐는지, 누가 경고를 받는지, 아직 쓸 수 있는 키인지, 어디서 폐기해야 하는지를 따로 판단해야 한다. 탐지 유형이 추가됐다는 사실과 유출 사고가 자동으로 처리된다는 주장은 서로 다르다.
| 제공자 | 10월 5일 공지의 탐지 유형 |
|---|---|
| Lovable Labs | lovable_api_key |
| Pydantic Services Inc. | logfire_token |
| Pydantic Services Inc. | pydantic_ai_gateway_api_key |
| Supabase | supabase_oauth_access_token |
| Supabase | supabase_scoped_personal_access_token |
GitHub 공식 공지의 식별자다. 각 유형의 최초 지원일, 유효성 검사·푸시 차단 지원을 모두 같은 의미로 표시한 표는 아니다.
경고, 제공자 통보, 푸시 차단은 각각 다른 기능이다
가장 먼저 구분할 것은 탐지 이후의 전달 경로다. 사용자 경고는 저장소의 보안 화면에서 개발자가 확인한다. 파트너 통보는 공개 저장소에서 발견한 인증정보를 해당 서비스 제공자에게 전달하는 별도 경로다. 제공자는 이를 받아 키를 회수하거나 교체하는 등의 조치를 할 수 있다. 파트너 통보 자체는 사용자 경고 목록에 그대로 나타나는 항목이 아니다.
Lovable의 파트너 참여를 설명한 공지는 이 두 번째 경로를 가리킨다. 그렇다고 모든 Lovable 키가 발견 즉시 동일한 방식으로 폐기된다거나, 이번에 나열된 Supabase·Pydantic 유형도 전부 같은 자동 조치를 받는다고 확대해서 해석할 수는 없다. 공급자에게 전달됐다는 사실과 실제로 키가 더 이상 작동하지 않는다는 사실은 따로 확인해야 한다.
Push protection은 그보다 앞단에서 작동한다. 이미 올라온 기록에서 키를 찾는 대신, 지원되는 인증정보를 포함한 커밋이 원격 저장소로 들어오려는 시점에 차단한다. 반면 유효성 검사는 발견된 값이 실제로 사용할 수 있는 인증정보인지 확인하는 기능이다. 탐지·차단·유효성 검사·파트너 통보는 한 묶음의 기능 이름이 아니라 서로 다른 지원 항목이다.
따라서 실제 도입 판단에는 공식 지원 패턴 표를 함께 봐야 한다. 제공자 이름뿐 아니라 User alert, Push protection, Validity check 열을 각각 확인하는 방식이다. GitHub 문서는 푸시 차단이 자신 있게 식별할 수 있는 최신 토큰 형식을 우선 지원한다고 설명한다. 이 글에서는 개별 행의 지원 상태를 확인하지 못한 다섯 유형에 대해 차단·유효성 검사가 모두 가능하다고 표시하지 않았다.
새 탐지기가 추가되면 과거 커밋도 살펴본다
Secret scanning의 대상은 현재 기본 브랜치에 보이는 파일만이 아니다. GitHub 문서는 저장소 전체 Git 기록과 모든 브랜치를 검사한다고 설명한다. 새 키 형식에 대한 지원이 추가되면 기존 저장소를 주기적으로 다시 살펴보기도 한다. 오래전에 지웠다고 생각한 설정 파일의 값이 뒤늦게 경고로 나타날 수 있는 이유다.
예를 들어 첫 커밋에 실제 토큰을 넣고 다음 커밋에서 환경변수로 바꾼 프로젝트를 생각해 보자. 최신 파일에서는 문자열이 사라졌어도 과거 커밋에는 남아 있을 수 있다. 이것은 기능 동작을 설명하기 위한 가상 상황이지, 특정 저장소에서 직접 유출을 확인했다는 뜻은 아니다. 경고가 나온 위치와 커밋을 확인해야 현재 파일 검색만으로 놓치기 쉬운 기록을 찾을 수 있다.
이용 조건은 저장소 공개 여부와 계정 형태에 따라 달라진다. 공개 저장소에서는 Secret scanning이 무료로 자동 실행된다. 조직 소유의 비공개·내부 저장소에서는 GitHub Team 또는 Enterprise Cloud에서 Secret Protection을 활성화하는 조건 등을 확인해야 한다. 공개 저장소에서 쓸 수 있다는 설명을 모든 개인 비공개 저장소에도 그대로 적용해서는 안 된다.
또한 경고가 없다는 결과는 비밀정보가 전혀 없다는 증명이 아니다. 탐지기는 지원하는 형식과 조건에 따라 작동하며 모든 문자열의 의도를 알아내는 것은 아니다. 팀에서는 새 탐지기 추가 소식에 맞춰 미처리 경고를 다시 확인하되, 환경설정·테스트 코드·배포 스크립트에 실제 인증정보를 넣지 않는 기본 관리도 함께 유지하는 편이 낫다.
경고 화면에서는 토큰 종류와 유효 상태를 먼저 읽는다
저장소에서 Security and quality 탭을 열고, 왼쪽 Vulnerability alerts 아래의 Secret scanning으로 들어가면 경고 목록을 볼 수 있다. 화면에 탭이 보이지 않으면 더보기 메뉴와 본인의 접근 권한을 확인한다. 목록에서 해당 경고를 열어 인증정보 유형과 발견 위치를 확인하고, 필요하면 담당자를 지정한다. 이번 변경을 확인하려고 실제 키를 일부러 커밋할 필요는 없다.
미처리 항목이 많다면 검색창의 필터가 도움이 된다. is:open은 열린 경고를, secret-type은 특정 탐지 유형을 고르는 조건이다. 예를 들어 아래 문자열은 이번 공지에 나온 Supabase 개인 접근 토큰 경고를 최신 생성 순서로 좁히는 문서 기반 예시다. 터미널 명령이 아니라 GitHub 경고 목록의 검색창에 넣는 조건이며, 실제 계정의 결과를 조회한 것은 아니다.
유효 상태가 표시된다면 active는 제공자에게 확인했을 때 아직 활성화된 키라는 뜻이다. unknown은 안전하다는 뜻이 아니다. 해당 형식의 검증을 지원하지 않거나 검증을 완료하지 못한 상태일 수 있다. inactive여도 과거에 악용되지 않았다는 증거가 되지는 않는다. 상태 표시를 대응 우선순위의 참고 자료로 쓰고, 노출 시점과 사용 기록까지 함께 확인해야 한다.
기본 유효성 검사와 일부 파트너 형식에 대한 추가 검사는 이용 조건도 다르다. 모든 경고에서 같은 버튼이나 메타데이터가 보인다고 가정하지 않는 편이 안전하다. 담당자는 키 값을 채팅에 복사하기보다 경고 링크, 저장소, 발견 경로, 제공자, 담당 서비스와 대응 상태를 공유하면 된다. 조사 과정에서 같은 비밀정보를 다른 기록에 다시 남기는 일을 줄일 수 있다.
is:open secret-type:supabase_scoped_personal_access_token sort:created-desc파일 삭제보다 먼저 키의 사용을 막아야 한다
유출된 키를 발견했을 때 핵심 조치는 그 키로 더 이상 서비스를 호출하지 못하게 만드는 것이다. GitHub의 대응 문서는 공개된 비밀정보를 이미 노출된 것으로 간주하고 제공자 쪽에서 회수하거나 교체하라고 안내한다. 저장소를 비공개로 바꾸거나 파일을 삭제하는 것만으로, 이미 복사된 키의 권한이 사라지지는 않는다.
실무에서는 키를 바로 폐기했을 때 운영 서비스가 멈추는지도 함께 고려해야 한다. 먼저 어떤 서비스와 배포 환경이 그 값을 쓰는지 파악한다. 서비스 연속성을 유지해야 한다면 대체 키를 발급하고 사용하는 곳을 바꾼 뒤 기존 키를 폐기하는 흐름을 검토할 수 있다. 다만 공개 노출이나 악용 징후가 있으면 피해를 줄이기 위한 긴급 회수가 우선일 수 있으므로 담당자와 위험도를 판단해야 한다.
교체 후에는 설정을 저장했다는 사실보다 실제 요청이 새 키로 처리되는지를 확인하는 것이 중요하다. 웹 서버와 작업 스케줄러가 서로 다른 환경변수를 쓰거나, 이전 배포가 계속 실행 중일 수 있기 때문이다. 이어 제공자의 접근·사용 기록에서 의심스러운 활동이 있는지 살펴본다. 여기의 순서는 공식 대응 원칙을 운영 상황에 맞게 풀어 쓴 예시이며, 모든 서비스에 동일한 교체 명령이 있다는 의미는 아니다.
마지막으로 저장소의 노출 지점을 정리하고 경고를 처리한다. GitHub는 파일에서 키가 삭제됐다는 이유만으로 경고를 자동 종료하지 않는다. 실제 폐기를 확인한 다음 Close as에서 그에 맞는 사유를 고르고, 조사 내용과 조치 시점을 기록한다. 기록에는 키 자체를 넣지 않는다. 과거 Git 기록을 재작성하는 정리는 협업에 영향을 줄 수 있으므로 인증정보 회수와 구분해서 계획해야 한다.
다음 업로드를 막는 설정도 따로 확인하자
사고를 처리한 뒤에는 동일한 값이 다시 커밋되는 경로를 줄여야 한다. 저장소 단위의 푸시 차단 설정은 Settings의 Advanced Security에서 확인한다. 필요한 경우 Secret Protection을 켠 뒤 Push protection을 활성화하는 순서다. 저장소 관리자 등의 권한과 이용 조건이 필요하며, 이미 조직에서 정한 보안 설정이 있다면 그 정책도 함께 확인한다.
명령줄에서 푸시가 차단됐다면 GitHub가 알려 준 위치를 먼저 읽는다. 한 번의 푸시에 여러 커밋이 포함될 수 있으므로 최신 파일에서만 키를 지운 뒤 다시 올리면, 앞선 커밋에 남아 있는 값 때문에 계속 차단될 수 있다. 공식 문서는 푸시에 포함된 모든 관련 커밋에서 비밀정보를 제거해야 한다고 설명한다. 이미 공유된 기록과 아직 올리지 않은 로컬 기록도 구분해야 한다.
이때 차단을 피하는 방법부터 찾는 것보다 실제 비밀정보인지 확인하고 안전한 값으로 바꾸는 것이 우선이다. 예시 설정에는 작동하지 않는 자리표시자만 남기고, 실제 값은 배포 환경의 비밀정보 관리 기능 등 코드와 분리된 위치에서 전달한다. .gitignore는 앞으로 추적하지 않을 파일을 지정하는 데 도움을 주지만, 이미 커밋된 키를 회수하는 기능은 아니다.
새 유형이 발표됐다는 이유로 차단 기능의 적용 범위까지 추측하지는 말자. 이번 공지의 다섯 식별자를 탐지 목록으로 이해하고, 현재 지원 표와 자신의 저장소 설정을 함께 확인하면 된다. 공개 저장소에서 제공되는 개인 단위 보호와 저장소 관리자 설정도 같은 것으로 혼동하지 않아야 한다. 이 글의 예시는 저장소 단위 설정과 실제 경고 확인에 초점을 맞췄다.