NHI Kill Chain: Over-shared Key — Stripe 키 하나가 14개 저장소에 들어있고, 주인은 아무도 모른다
Stripe API 키 하나가 3년간 14곳에 복사되었습니다. QA 리포가 공개 전환되면서 키가 노출 — 폐기하면 14개 서비스가 동시에 죽는 상황.

"이 키 폐기하면 14곳이 동시에 죽습니다"
2025년 초. 직원 200명 규모의 B2B SaaS 기업. 마이크로서비스 아키텍처, 40개가 넘는 리포지토리, 시리즈 B를 막 마무리한 성장 단계의 회사다.
3년 전, 결제 서비스를 처음 만들 때 시니어 백엔드 엔지니어 P가 Stripe live API key를 생성했습니다. 처음에는 payment-service 리포 하나에만 존재했습니다. 단 하나. 깔끔했습니다.
그런데 시간이 흐르면서 키는 조용히 퍼져 나갔습니다.
QA 팀이 결제 연동 E2E 테스트를 만들면서 e2e-tests 리포에 키를 복사했습니다. 환불 처리 서비스를 새로 개발하면서 refund-service에 같은 키가 들어갔습니다. 정산 배치 서비스에도. 모바일 앱 백엔드에도. Slack #payments 채널에 누군가 "테스트용 키"라며 고정 메시지로 올렸다. 실은 live key였습니다. Confluence의 결제 연동 가이드에 "예제"로 포함되었다. Jenkins 파이프라인 3개에 환경변수로 주입되었다. 개발자 3명의 로컬 .env 파일에 복사되었다.
3년이 지난 지금, 같은 Stripe live API key가 14곳에 존재합니다. 원래 키를 만든 P는 1년 전에 퇴사했습니다. 이 키의 주인이 누구인지 물으면 아무도 대답하지 못합니다.
보안팀 리드가 키 로테이션을 제안했을 때, 결제팀 팀장의 반응은 이랬다.
"이 키를 로테이션하면 결제 서비스, 환불 서비스, 정산 배치, 모바일 백엔드가 동시에 멈춥니다. 14곳 전부 어디 있는지 파악하고 동시에 업데이트해야 하는데, 저는 이 중 5곳만 압니다."
로테이션은 무기한 연기되었다.
그러던 어느 날, 14곳 중 가장 약한 고리가 터졌습니다. QA 리포가 내부 코드 리뷰 편의를 위해 잠시 public으로 전환되었다. 전환한 사람은 이 리포에 Stripe live key가 하드코딩되어 있다는 사실을 몰랐다. GitHub의 공개 리포를 스캔하는 자동화된 봇은 키를 4분 만에 발견했습니다.
공격자는 이 키로 Stripe API에 접근했습니다. 고객 결제 정보를 조회하고, 환불 사기를 실행했습니다. 보안팀이 이상 거래를 감지하고 키를 즉시 폐기했을 때, 14곳 중 나머지 13곳이 동시에 장애를 일으켰다. 결제가 멈추고, 환불이 멈추고, 정산이 멈추고, 모바일 앱에서 결제 오류가 쏟아졌습니다.
키가 어디에 존재하는지 전수 조사에 2일이 걸렸다. 14곳 모두를 새 키로 업데이트하는 데 4일이 걸렸다. 그 사이 약 $50,000의 환불 사기 피해가 발생했습니다.
이 키는 왜 위험한가
Over-shared Key는 하나의 크리덴셜이 복사, 공유, 하드코딩을 통해 다수의 시스템에 퍼진 상태를 뜻합니다. 핵심 위험은 키 자체가 아니라, 키가 어디에 있는지 아무도 전체를 파악하지 못한다는 것입니다.
크리덴셜은 왜 퍼지는가요. 원인은 구조적입니다.
첫째, 개발 속도가 보안 절차보다 빠릅니다. 새 서비스를 만들 때 Secrets Manager에 별도 키를 프로비저닝하고, 권한을 분리하고, 접근 정책을 설정하는 데에는 시간이 걸린다. "일단 되는 키"를 .env에 복사하는 건 30초면 끝난다. 스프린트 마감을 앞둔 개발자에게 어느 쪽이 선택되는지는 자명합니다.
둘째, "임시"라고 시작한 것은 영구가 됩니다. 모든 복사는 "나중에 분리할 거야"라는 전제로 시작됩니다. 하지만 되돌아가서 분리하는 일은 로드맵에 올라가지 않습니다. 임시 코드는 프로덕션이 되고, 임시 키는 영구 키가 됩니다.
셋째, 조직이 커지면서 키의 히스토리가 사라집니다. 키를 만든 사람이 퇴사하고, 그 키를 복사한 사람이 팀을 옮기고, 누가 어디에 왜 넣었는지 아는 사람이 사라집니다. 남는 건 14곳에 동일하게 존재하는 하나의 키와 "그거 건드리면 뭐가 터져요"라는 경고뿐입니다.
이 현실에 대해 CISO가 가장 많이 하는 말과 그 현실의 괴리를 보겠습니다.
"키 로테이션 정책이 있습니다." 로테이션 정책이 있어도, 그 키가 14곳에 분산되어 있다는 사실을 모르면 정책은 종이 위에만 존재합니다. 3곳만 알고 로테이션하면 나머지 11곳이 장애를 냅니다.
"Secrets Manager를 쓰고 있습니다." 맞습니다. 초기의 1곳, payment-service는 Secrets Manager에서 키를 가져옵니다. 하지만 나머지 13곳은 하드코딩된 복사본입니다. Secrets Manager는 원본의 수명주기만 관리합니다. 복사본은 관리 밖입니다.
"서비스별로 키를 분리하라고 했습니다." 지시는 했지만, 현장에서는 "일단 되는 키"를 복사해서 씁니다. 새로운 키를 생성하고, 최소 권한을 설정하고, 배포 파이프라인을 업데이트하는 일은 추가 작업입니다. 마감에 쫓기는 팀에서 추가 작업은 생략됩니다.
GitGuardian의 2025 State of Secrets Sprawl 보고서는 이 문제의 규모를 정량적으로 보여줍니다. GitHub에서 발견된 시크릿의 90% 이상이 5일 후에도 유효했습니다. 시크릿은 발견되어도 폐기되지 않습니다. 여러 곳에 퍼져 있으면 폐기 자체가 두려운 행위가 되기 때문입니다.
Over-shared Key의 보안 수준은 14곳 중 가장 약한 1곳에 의해 결정됩니다. 13곳이 완벽하게 관리되어도, QA 리포 하나가 public으로 전환되면 키는 유출됩니다. 공격자는 가장 견고한 성벽을 넘지 않습니다. 가장 낮은 울타리를 넘는다.

Kill Chain -- Over-shared Key가 조직 전체 장애로 이어지는 5단계

Over-shared Key의 공격 체인은 다른 NHI 위험과 구별되는 특징이 있습니다. 키가 유출되는 지점은 하나지만, 피해는 키가 존재하는 모든 곳에서 동시에 발생합니다. 5개 단계를 분석합니다.
1단계: Single Point of Origin -- 하나의 키가 태어난다. 시작은 정당합니다. 시니어 엔지니어 P가 Stripe 결제 연동을 위해 live API key를 생성합니다. payment-service 리포에 넣고, 서비스는 잘 돌아갑니다. 이 시점에서 키는 1곳에만 존재하고, 소유자는 명확합니다. 위험은 제로에 가깝다.
2단계: Organic Sprawl -- 조용한 증식. 시간이 흐르면서 키는 퍼집니다. QA 팀이 E2E 테스트에 복사합니다. 다른 팀이 환불 서비스를 만들면서 복사합니다. Slack에 공유됩니다. Confluence에 올라갑니다. Jenkins에 들어갑니다. 개발자의 로컬 .env에 들어갑니다. 각 복사 시점에 누구도 "이게 위험하다"고 생각하지 않습니다. "이미 쓰고 있는 키니까" 복사하는 것이 합리적으로 느껴진다. 키는 1곳에서 14곳으로 퍼지지만, 어디에도 이 확산을 추적하는 시스템은 없습니다.
3단계: Ownership Dissolution -- 주인이 사라집니다. 키를 만든 P가 퇴사합니다. P의 HR 오프보딩은 완료되지만, 이 키가 P의 것이라는 연결은 어디에도 기록되어 있지 않다. 14곳에 같은 키가 있지만, 누구의 책임인지 묻는 질문에 아무도 답하지 못합니다. 누군가 로테이션을 제안하면 "그거 건드리면 뭐가 터질지 모릅니다"라는 대답이 돌아옵니다. 위험은 인지되지만, 행동은 무기한 연기됩니다.
4단계: Weakest Link Breach -- 14곳 중 1곳이 뚫린다. 14곳 중 보안이 가장 약한 곳에서 유출이 발생합니다. QA 리포가 실수로 public 전환되거나, 개발자의 로컬 .env가 인포스틸러에 의해 탈취되거나, Slack 메시지가 외부에 노출됩니다. 키가 1곳에만 있었다면 유출 가능성은 1곳의 보안 수준에 달려 있습니다. 14곳에 있으면 유출 가능성은 14배가 아니다. 14곳 중 가장 취약한 곳의 보안 수준이 전체 키의 보안 수준이 됩니다.
5단계: Cascading Response Failure -- 대응이 재앙이 됩니다. 유출을 감지하고 키를 즉시 폐기합니다. 그 순간, 키가 존재하는 나머지 13곳이 동시에 장애를 일으킵니다. 결제가 멈추고, 환불이 멈추고, 정산이 멈추고, 모바일 앱이 오류를 뿜는다. 보안 사고 대응과 프로덕션 장애 복구가 동시에 벌어진다. 키가 어디에 있는지 전수 조사를 해야 하는데, 14곳 중 5곳만 파악되어 있으므로 나머지 9곳을 찾는 데만 2일이 걸린다. 그 사이 공격자는 이미 획득한 데이터를 활용하고 있습니다.
왜 기존 보안 체계로는 잡히지 않는가

Over-shared Key 문제는 기존 보안 도구의 설계 범위 바깥에 존재합니다. 각 도구는 자기 영역에서는 잘 작동하지만, 크리덴셜 확산이라는 문제를 해결하도록 설계된 도구는 없습니다.
Secrets Manager는 원본만 관리합니다. AWS Secrets Manager, HashiCorp Vault, Azure Key Vault -- 이 도구들은 시크릿의 저장과 접근 제어에 최적화되어 있습니다. payment-service가 Vault에서 Stripe key를 안전하게 가져오는 구조를 만들 수 있습니다. 하지만 누군가 그 키 값을 복사해서 refund-service의 config.yaml에 하드코딩하면, Vault는 이 사실을 알 방법이 없습니다. Vault가 관리하는 건 원본입니다. 복사본은 범위 밖입니다.
Secret scanning은 "존재"는 알지만 "중복"은 모릅니다. GitHub Secret Scanning, GitLeaks, TruffleHog -- 이 도구들은 리포지토리에서 시크릿의 존재를 탐지합니다. "이 리포에 Stripe key가 있다"는 알려주지만, "이 키가 다른 13곳에도 있다"는 알려주지 않습니다. 각 탐지 결과는 독립적인 알림입니다. 같은 키가 14곳에서 발견되었다는 사실을 연결해주는 도구는 없습니다.
IAM과 RBAC는 키 자체의 권한만 관리합니다. Stripe의 API key 권한이 결제 읽기/쓰기로 적절히 설정되어 있다고 하자. 하지만 같은 키가 14곳에 복사되어 있다는 사실은 IAM의 관심사가 아니다. IAM은 "이 키가 무엇을 할 수 있는가"를 관리하지, "이 키가 어디에 있는가"를 추적하지 않습니다.
로그 모니터링은 사용 패턴을 보지만 복사 패턴은 보지 못합니다. Stripe의 API 로그에서 같은 키로 들어오는 요청이 여러 IP에서 오는 것을 볼 수 있습니다. 하지만 "이건 정상적인 여러 서비스의 요청인가, 비정상적인 외부 접근인가"를 구분하려면 키가 어디에 배포되어 있는지 알아야 합니다. 14곳 전부를 파악하고 있지 않으면, 15번째 접근이 공격인지 판단할 수 없습니다.
수동 인벤토리는 시작한 시점에 이미 outdated다. 스프레드시트에 "어떤 키가 어디에 있는가"를 정리하는 작업을 할 수 있습니다. 하지만 개발자가 다음 날 새 서비스에 키를 복사하면 스프레드시트는 즉시 현실과 달라집니다. 수동 추적은 변화 속도를 따라잡을 수 없습니다.
근본적인 문제는 이것입니다. 기존 도구들은 "이 시크릿이 이 시스템에 존재한다"는 각각 알 수 있지만, "같은 시크릿이 여러 시스템에 걸쳐 몇 곳에 존재하는가"를 보여주는 도구는 없습니다. 크리덴셜의 cross-source 중복 탐지는 기존 보안 스택의 빈자리다.
실제 사례와 업계 데이터
Over-shared Key는 이론적인 위험 범주가 아니다. 주요 보안 사고의 반복적 원인이며, 업계 데이터가 이 문제의 규모를 수치로 보여줍니다.
OWASP NHI Top 10은 Secret Sprawl -- 시크릿의 통제되지 않은 확산 -- 을 비인간 아이덴티티 보안의 핵심 위험으로 분류합니다. 하나의 크리덴셜이 여러 시스템으로 퍼지면 공격 표면이 확대되고, 사고 대응 시간이 길어지며, blast radius 파악이 불가능해진다.
CSA의 2026 State of NHI Security 보고서에 따르면, 조직의 12%만이 NHI 기반 공격을 방지할 수 있다고 높은 자신감을 보였습니다. 크리덴셜 확산이 관리되지 않는 상태에서 자신감을 가지기 어려운 건 당연합니다. 키가 어디에 있는지 모르는데 어떻게 보호하겠는가요.
Verizon의 2025 Data Breach Investigations Report는 분석 대상 침해의 약 20%에서 크리덴셜 악용이 관여했다고 밝혔다. 도난, 유출, 방치된 크리덴셜은 해마다 가장 일관되고 효과적인 침투 벡터다.
2022년 Uber 침해 사고는 크리덴셜 체이닝의 전형적 사례다. 공격자는 내부 시스템 -- PowerShell 스크립트, 네트워크 공유 -- 에서 발견한 크리덴셜을 사용해 AWS, Google Workspace, Slack, HackerOne까지 도달했습니다. 내부 시스템 곳곳에 같은 크리덴셜이 퍼져 있었고, 하나를 발견하면 나머지에 접근할 수 있었다. Over-shared Key가 만드는 것이 바로 이런 체이닝 경로다.
GitGuardian의 2025 State of Secrets Sprawl 보고서는 하나의 시크릿이 평균적으로 여러 위치에 복제되어 존재한다고 보고합니다. 기업 내 시크릿 확산(secret sprawl)은 단일 키가 수십 곳에 퍼지는 현상으로, 발견 후에도 완전한 정리가 이루어지지 않습니다. 90% 이상의 시크릿이 발견 후 5일이 지나도 유효 상태를 유지합니다. 이유는 단순합니다. 여러 곳에 퍼진 키를 폐기하면 서비스 장애가 나기 때문입니다. "위험한 건 아는데 건드릴 수 없다"는 상황이 반복됩니다.
결제 시스템 관련 크리덴셜 확산은 특히 위험합니다. PCI DSS 컴플라이언스에서 카드 데이터 접근 키는 엄격한 관리 대상이지만, 현실에서 Stripe, PayPal, Adyen 같은 결제 게이트웨이의 live API key가 개발/테스트 환경에 하드코딩되어 퍼지는 사례는 감사 때마다 발견됩니다. 컴플라이언스 체크리스트가 통과되어도, 체크리스트가 묻지 않는 곳에 키가 존재합니다.
탐지 및 대응 가이드
Over-shared Key를 탐지하고 대응하려면, 기존의 "이 시스템에 시크릿이 있는가"라는 질문을 "이 시크릿이 몇 개의 시스템에 있는가"로 바꿔야 합니다.
크리덴셜 중복 탐지 체계를 구축하세요. 단일 시스템 내 시크릿 스캔이 아니라, 여러 소스에 걸쳐 동일한 시크릿이 몇 곳에 존재하는지 식별하는 cross-source 중복 탐지가 필요합니다. GitHub 리포, Slack 메시지, Confluence 문서, CI/CD 환경변수, 클라우드 Secrets Manager, 개발자 로컬 환경 -- 이 모든 곳을 하나의 시야에서 볼 수 있어야 합니다. 동일 키 해시가 3곳 이상에서 발견되면 Over-shared Key로 분류합니다.
서비스별 키 분리 정책을 강제하세요. 하나의 서비스에는 하나의 전용 키. 이 원칙을 가이드라인이 아닌 자동화된 정책으로 강제해야 합니다. CI/CD 파이프라인에서 같은 키가 두 개 이상의 서비스에 사용되면 배포를 차단하는 게이트를 설정합니다. "일단 되는 키"를 복사하는 것보다 새 키를 생성하는 것이 더 빠르고 쉬운 프로세스를 만듭니다.
Blast radius를 미리 매핑하세요. 매 분기, 또는 크리덴셜 인벤토리 변경 시마다 각 키의 blast radius를 매핑합니다. "이 키가 폐기되면 어떤 서비스가 영향받는가"를 사전에 파악합니다. blast radius가 3개 서비스 이상인 키는 즉시 분리 대상입니다.
단계적 로테이션 전략을 수립하세요. Over-shared Key를 발견했을 때 즉시 폐기는 최악의 선택일 수 있습니다. 대신 다음 순서를 따른다. (1) 키가 존재하는 모든 위치 파악, (2) 각 위치에 별도의 새 키 생성 및 배포, (3) 모든 위치가 새 키로 전환되었는지 확인, (4) 그때 비로소 구 키 폐기. 이 과정을 "controlled rotation"이라 합니다.
활성 사고 대응 시에는 blast radius를 감수하세요. 키가 이미 악용되고 있는 상황이라면 단계적 로테이션을 기다릴 시간이 없습니다. 즉시 폐기하고, 발생하는 서비스 장애를 동시에 복구합니다. 이때 키가 어디에 있는지 미리 매핑되어 있으면 복구 시간을 4일에서 수 시간으로 단축할 수 있습니다. 매핑이 없으면 전수 조사부터 시작해야 합니다.
시크릿 복사를 감시하는 모니터링을 도입하세요. 새 리포나 새 서비스에 기존 키와 동일한 시크릿이 커밋되면 즉시 알림을 보냅니다. 확산은 초기에 잡아야 합니다. 14곳으로 퍼진 후에 정리하는 것과 2곳에서 잡는 것은 난이도가 완전히 다릅니다.
시크릿 탐지 구현에 대한 더 자세한 내용은 Secret Detection: 2026년 완벽 가이드와 Git Secret Scanning: 완벽 구현 가이드를 참고하세요.
Cremit Argus가 Over-shared Key를 탐지하는 방법
Over-shared Key를 방치하는 근본 원인 -- 키가 어디에 있는지 모른다, 같은 키의 중복을 파악할 수 없다, blast radius를 계산할 수 없다 -- 은 정확히 Cremit Argus가 해결하도록 설계된 문제다.
Argus는 cross-source 크리덴셜 중복 탐지를 수행합니다. GitHub 리포지토리, Slack 워크스페이스, Confluence 문서, CI/CD 파이프라인, 클라우드 환경 -- 이 모든 소스에서 발견된 시크릿을 대조하여 동일 키가 몇 곳에 존재하는지 실시간으로 보여줍니다. payment-service의 Stripe key와 e2e-tests의 Stripe key가 동일한 값이라는 사실을 Argus가 연결합니다. 기존 secret scanning 도구가 각각 독립된 알림을 생성하는 것과 달리, Argus는 "이 키는 14곳에 있습니다"라는 하나의 사실을 보여줍니다.
Argus는 sprawl map을 시각화합니다. 하나의 키가 어떤 시스템, 어떤 리포, 어떤 채널에 퍼져 있는지를 방사형 다이어그램으로 보여줍니다. CISO가 "이 키의 blast radius가 어디까지인가"라는 질문에 즉시 답할 수 있습니다. 로테이션 전에 영향 범위를 파악하고, 단계적 전환 계획을 세울 수 있습니다.
Argus는 새로운 확산을 실시간으로 감지합니다. 기존에 추적 중인 키와 동일한 값이 새로운 소스에 나타나면 즉시 알린다. 14곳으로 퍼지기 전에, 2곳에서 잡는다. 시크릿 확산은 시간이 지나면 기하급수적으로 어려워집니다. 초기 탐지가 핵심입니다.
Cremit Argus로 Over-shared Key를 식별하고 제거하는 방법을 확인하세요.
NHI Kill Chain 시리즈 안내

이 글은 NHI Kill Chain 시리즈의 네 번째 글입니다. 아홉 편의 시리즈를 통해 조직 내부에 숨어 있는 가장 위험한 NHI 크리덴셜 유형을 분석합니다. 각 유형은 독립적이면서도 서로 연결된 위험을 나타냅니다.
공개 리포에 노출된 키(Public Key)가 로테이션되지 않으면 Aged Key가 됩니다. 퇴사자의 키(Ghost Key)가 폐기되지 않으면 Zombie Key가 됩니다. 하나의 키가 여러 곳에 복사되면(Over-shared Key) 사고 대응 자체가 재앙이 됩니다. 하나의 크리덴셜 관리 실패가 어떻게 다른 위험 범주로 연쇄되는지 이해하는 것이 이 시리즈의 핵심입니다.
- Public Key -- .env가 GitHub에 올라간 뒤 4분 동안 벌어지는 일
- Ghost Key -- 퇴사한 개발자의 AWS 키는 아직 출근 중이다
- Aged Key -- 3년간 프로덕션을 지탱한 골동품 키
- Over-shared Key -- Stripe 키 하나가 14개 저장소에 들어있고, 주인은 아무도 모른다 (현재 글)
- Zombie Key -- 코드에서 삭제해도 키는 죽지 않는다 (예정)
- Drifted Key -- CI/CD 봇이 DB 비밀번호를 Jira에 자동 첨부했다 (예정)
- Shadow Key -- Secrets Manager 바로 옆에 하드코딩된 조용한 키 (예정)
- Unattributed Key -- 이 키는 누가 만들었는가요? 아무도 모른다 (예정)
- 시리즈 종합 -- NHI Kill Chain 전체 프레임워크와 통합 대응 가이드 (예정)
이전 글: [NHI Kill Chain: Aged Key -- 3년간 프로덕션을 지탱한 골동품 키](/ko/blog/nhi-kill-chain-aged-key)
다음 글: NHI Kill Chain: Zombie Key -- 코드에서 삭제해도 키는 죽지 않는다
Cremit은 NHI 보안 기업입니다. [cremit.io에서 더 알아보세요.](https://cremit.io)
