본문으로 건너뛰기
NEW · Blast Radius: 유출된 API 키 대응 플레이북 (AWS·GCP·Azure)
블로그로 돌아가기

Zeabur는 왜 두 달 만에 다시 뚫렸나: 8월 교체에서 빠진 키가 10월에 쓰였습니다

대만 PaaS Zeabur가 두 달 사이 두 번 침해된 뒤 12월 31일 서비스를 종료합니다. 10월 공격자는 8월 사고 뒤에도 교체되지 않은 평문 관리자 토큰과 AWS 키로 9개 리전의 공유 클러스터와 플랫폼 DB에 들어갔습니다. 확인된 사실과 가설을 나누고, 사용자가 할 일과 다른 팀이 가져갈 점검 목록을 정리했습니다.

김동현
작성자
김동현
발행
13 분1,410 어절
Share:
8월 사고 뒤 교체된 자격증명은 낮은 블록으로, 교체되지 않은 관리자 토큰과 AWS 키는 노란 블록으로 남아 10월 공격 경로가 된 장면
Zeabur 8월 사고 전후의 자격증명: 관리자 Legacy API Key와 AWS 루트 키는 교체됐고, GitHub App 개인 키는 8월 31일 교체 뒤 10월에 다시 조회됐습니다. 설정 레포에 평문으로 있던 공유 클러스터 관리자 토큰과 내부 AWS 키, GCP 서버 root 비밀번호는 그대로 남아 10월에 쓰였습니다.

두 번의 사고, 그리고 서비스 종료

대만의 배포 플랫폼 Zeabur가 2026년 10월 17일 서비스 종료를 발표했습니다. 12월 1일부터 전용 서버 갱신이 막히고 공유 클러스터 서비스가 멈추며, 12월 31일에 모든 서버와 클러스터가 꺼집니다. 창업자는 종료 이유로 성장의 한계와 유지하기 어려워진 시스템 복잡도, 그리고 올해 두 번의 보안 사고를 함께 들었습니다.

두 번째 사고는 10월 14일 01:36(UTC)에 시작됐습니다. 공격자는 Zeabur 내부 자격증명으로 9개 리전의 공유 클러스터, AWS, GCP 전용 서버 일부에 들어갔고, 마지막에는 플랫폼 DB를 읽었습니다. 환경 변수 레코드 3,218,965건과 계정 321,810개 정보가 그 DB에 있었습니다. 경보는 울리지 않았습니다. 조사는 15일 13:56에 사용자 신고를 받고 시작됐는데, 첫 자격증명 사용 뒤 약 36시간이 지난 시점입니다.

이 글에서 가장 중요한 사실은 하나입니다. 10월 공격에 쓰인 관리자 토큰과 AWS 키는 8월 사고 뒤 교체 대상에서 빠져 있던 키입니다. Zeabur는 8월 보고서에서 "모든 내부 관리자 키를 비활성화하거나 교체했다"고 썼고, 10월 보고서에서 그 문장이 불완전했다고 정정했습니다.

확인된 사실과 아직 가설인 것

Zeabur 보고서로 확인된 사실(2026-10-19 1차 보고서 기준):

  • 공유 클러스터 관리자 토큰은 2024년 1월 10일에 만들어졌고 만료가 없었습니다. 2026년 1월부터 비공개 설정 레포에 평문으로 들어 있었습니다.
  • 같은 레포에 내부 AWS 키도 평문으로 있었습니다. 두 가지 모두 8월 사고 뒤 교체되지 않았습니다.
  • 클러스터 관리자 인터페이스는 공개 인터넷에서 접근할 수 있었습니다.
  • GCP 전용 서버 root 비밀번호는 서버 초기화 설정에 평문으로 있었습니다. 9월 3일에 발견됐지만 사고 전까지 고쳐지지 않았습니다.
  • 공격자는 GCP 전용 서버 101대(사용자 92명)에 root로 로그인했고, 50대에 SSH 키를 심었으며, 고객 서버 디스크 복사본 16개를 자기 VM에 붙였습니다.
  • 공유 클러스터에서 데이터베이스 서비스 865개에 명령이 실행됐습니다. 확인한 n8n 607개 중 602개는 암호화 키를 환경 변수에 두고 있었습니다.
  • 8월 뒤 Zeabur 권고에 따라 환경 변수를 자기 전용 서버로 옮긴 프로젝트는 플랫폼 DB 조회 범위 밖이었습니다.

아직 가설인 것:

  • 공격자가 설정 레포 자격증명을 어떻게 얻었는지는 확인되지 않았습니다. Zeabur는 8월에 유출된 GitHub App 개인 키를 가장 유력하게 보지만, 두 사고의 공격자 IP는 겹치지 않습니다. GitHub의 감사 기록 회신을 기다리고 있습니다.
  • 10월 10~13일의 익명 탐색과 SSH 시도가 같은 공격자인지는 증명되지 않았습니다.
  • 10월 16일 사용자 OpenAI 키 남용(약 1,107건)이 이번 유출에서 나왔는지는 가설입니다.

8월: NextChat 컨테이너에서 AWS 루트 키까지

8월 27일 사고는 고객이 공유 클러스터에 띄운 NextChat v2.16.1에서 시작됐습니다. 공격자는 MCP 기능의 권한 검사 결함(CVE-2026-7644)으로 컨테이너 안에서 코드를 실행했고, 공유 클러스터 내부망을 따라 라우팅 캐시에 닿았습니다. 도메인과 서비스를 연결하려고 만든 캐시였는데, Zeabur Legacy API Key도 함께 들어 있었습니다. 공격자는 키들을 차례로 시험해 팀 관리자 키를 찾았습니다.

그 관리자 키로 내부 관리 서비스의 환경 변수를 읽었고, 그 안에 오래 보관된 AWS 루트 키가 있었습니다. 이어 필요 이상의 권한을 가진 유지보수 잡의 DB 자격증명으로 운영 DB에 들어가 계정 정보와 프로젝트 환경 변수를 읽었습니다. 고객이 넣어 둔 서드파티 API 키, 클라우드 자격증명, DB 비밀번호, 서명 키가 그 대상이었습니다.

경계 네 개를 넘는 동안 공격자가 쓴 것은 모두 사람이 아닌 신원의 자격증명입니다. 캐시에 있던 API 키, 서비스 환경 변수에 있던 클라우드 키, 잡에 붙은 DB 계정이 그것입니다.

10월: 교체 목록 밖에 남은 자격증명

8월 사고 뒤 Zeabur는 확인된 내부 키를 교체하고 Legacy API Key 인증을 껐으며, 사용자에게 환경 변수를 교체하고 전용 서버로 옮기라고 권했습니다. 문제는 그 교체가 "유출이 확인된 키"를 기준으로 범위를 정했다는 점입니다. 설정 레포에 평문으로 있던 클러스터 관리자 토큰과 AWS 키, GCP 초기화 설정의 root 비밀번호는 그 목록에 없었습니다. 10월 공격은 정확히 그 세 가지로 진행됐습니다.

공격은 두 갈래로 나뉘었다가 합쳐졌습니다.

  • 공유 클러스터와 AWS. 01:36에 AWS 키, 01:40에 클러스터 관리자 토큰을 처음 썼습니다. 12:39에는 공유 클러스터의 모든 서비스 설정과 시크릿을 읽었습니다. 하나의 버킷용으로 만든 키가 계정의 모든 버킷을 읽을 수 있었고, 공격자는 그 키로 옛 클러스터 백업을 읽은 것으로 판단됩니다. 그 백업에 시크릿 관리 서비스의 키가 있었고, 공격자는 그 키로 운영 시크릿 약 53개를 읽었습니다. 내부망 관리자 자격증명, 플랫폼 DB 계정, GitHub App 개인 키가 여기에 들어 있었습니다.
  • GCP 전용 서버. 14일 13:40부터 평문 root 비밀번호로 서버 101대에 로그인했습니다. 15일 15:05에는 운영 GCP 키도 손에 넣었습니다.
  • 합류. 15일 15:30, 공격자는 앞에서 얻은 내부망 관리자 자격증명으로, 장악한 GCP 서버를 Zeabur 내부망 노드로 추가했습니다. 내부망 규칙이 그 노드에서 플랫폼 DB 접근을 허용했고, 공격자는 모든 데이터를 읽을 수 있는 "읽기 전용" 계정으로 16:10부터 16:47까지 DB를 읽었습니다.

대응 중에도 같은 문제가 한 번 더 나왔습니다. 대응 중 교체한 자격증명 일부를 16:00 백업이 다시 담았고, 공격자는 20:30에 그 자격증명을 썼습니다. 마지막 공격자 활동은 15일 21:05(AWS)입니다.

Zeabur만의 문제가 아닙니다

Zeabur가 스스로 적은 근본 원인을 정리하면, 대부분 NHI Kill Chain 시리즈에서 다룬 패턴입니다.

  • Aged Key. 클러스터 관리자 토큰은 2024년 1월에 만들어진 뒤 만료도 교체도 없었습니다. 공격자는 그 키가 살아 있던 기간 전부를 쓸 수 있었습니다.
  • Out of Scope Loophole. 8월 교체는 유출이 확인된 키를 기준으로 범위를 정했습니다. 설정 레포, 코드, 빌드 잡, 서버 초기화 설정, 백업에 흩어진 평문 자격증명은 그 범위 밖에 있었습니다. 인벤토리에 없는 키는 교체되지 않습니다.
  • Over-shared Key와 과도한 권한. 버킷 하나용 키가 모든 버킷을 읽었고, GCP 기본 서비스 계정은 프로젝트 쓰기 권한을 가졌으며, 읽기 전용 DB 계정은 모든 데이터를 읽었습니다. 키 하나가 털릴 때의 피해 범위는 권한이 정합니다.
  • Ghost Key. 운영을 끝낸 서비스의 배포 키가 종료 뒤 4개월 동안 유효했고, 15일 15:02에 설정 레포를 읽었습니다(공격자로 추정).
  • 시크릿을 담은 백업. 백업에 모든 시크릿이 들어 있었고, 백업 접근 키가 다른 시크릿과 같은 곳에 있었습니다. 교체한 값도 다음 백업이 다시 담았습니다.
  • 탐지. 16시간 넘게 이어진 공격자 활동에 경보가 하나도 없었습니다. 스토리지, GCP, GitHub 접근 기록도 불완전해서 무엇이 실제로 나갔는지 지금도 일부는 알 수 없습니다.

Zeabur 사례에서 가장 아픈 교훈은 사고 뒤 교체 범위를 어디까지 잡느냐입니다. "유출이 확인된 키만 교체"는 합리적으로 들리지만, 공격자가 어디까지 봤는지 모를 때는 공격자가 닿을 수 있었던 범위를 기준으로 잡아야 합니다. 그러려면 그 범위 안에 어떤 키가 있는지 먼저 알아야 합니다.

Zeabur 사용자라면 지금 할 일

Zeabur 권고를 순서대로 정리했습니다. 종료 일정이 있으니 교체와 이전을 함께 진행하세요.

  1. 환경 변수의 모든 자격증명 교체. API 키, 클라우드 키, DB 비밀번호, 서명·암호화 키가 대상입니다. 발급처에서 먼저 폐기하고, 새 값을 만든 뒤 재배포하세요. 8월 뒤 전용 서버로 옮긴 프로젝트도 그 서버가 침해된 호스트라면 교체 대상입니다.
  2. DB 안의 비밀번호와 토큰. 환경 변수를 바꿔도 DB 안의 비밀번호는 바뀌지 않습니다. DB 사용자 비밀번호를 바꾸고, DB에 저장된 세션·토큰·해시를 폐기하세요.
  3. n8n 사용자. 암호화 키를 바꾸고 모든 서드파티 자격증명을 다시 만드세요. 확인된 n8n의 대부분이 암호화 키를 환경 변수에 두고 있었습니다.
  4. new-api/one-api 사용자. 상위 AI 키를 폐기하고 접근 토큰을 다시 발급하세요.
  5. GCP 전용 서버 사용자. 침해된 것으로 보고 백업 뒤 재구축하세요. 바로 못 한다면 /root/.ssh/authorized_keys에서 @zeabur-pentest 주석이 붙은 키를 지우고, crontab·systemd·k3s 워크로드를 확인하고, root 비밀번호를 바꾸고 SSH 비밀번호 로그인을 끄세요.
  6. GitHub 연동 사용자. 10월 15일 15:05~18:54(UTC) 사이 Zeabur GitHub App의 clone·push, 새 배포 키, 웹훅 변경을 감사 로그에서 확인하세요.
  7. 청구서. 10월 14일 이후 각 발급처 청구를 확인하세요. GCP 전용 서버 사용자는 9월 1일부터 보세요.
  8. 이전 일정. 12월 1일에 공유 클러스터 서비스가 멈추고 전용 서버 갱신이 막힙니다. 각 서버 만료일 전에 백업과 이전을 끝내세요.

교체할 때는 같은 값이 복사된 곳을 함께 찾으세요. Zeabur 환경 변수에 넣은 키가 CI, 로컬 .env, 다른 클라우드 설정에도 있다면, Zeabur에서만 바꿔서는 교체가 끝나지 않습니다.

Zeabur를 쓰지 않아도 점검할 것

이번 사고의 원인은 대부분 배포 플랫폼이 아닌 회사에도 그대로 있습니다. 우리 팀에 다음이 있는지 확인해 보세요.

  • 만료가 없는 관리자 토큰이나 클라우드 키. 언제 만들어졌고 마지막으로 언제 교체됐는지 답할 수 있나요?
  • 비공개 레포, 인프라 설정, 서버 초기화 스크립트, 빌드 잡에 평문으로 들어간 자격증명. "비공개라서 괜찮다"는 레포 접근 권한이 하나만 새도 무너집니다.
  • 시크릿이 그대로 들어간 백업, 그리고 그 백업을 여는 키를 다른 시크릿과 같은 곳에 두는 구성.
  • 종료한 서비스의 배포 키, 웹훅 토큰, 서비스 계정.
  • 이름보다 넓은 권한. "읽기 전용" DB 계정이 무엇을 읽을 수 있는지, 버킷 하나용 키가 실제로 몇 개 버킷을 여는지.
  • 지난 사고 뒤 교체 목록. 유출이 확인된 키만 바꿨다면, 같은 시스템에 있던 나머지 키가 지금도 유효한지 확인하세요.

Cremit이 볼 수 있는 것과 볼 수 없는 것

Zeabur 내부 설정 레포나 플랫폼 DB를 저희가 볼 수는 없습니다. "내 키가 Zeabur DB에서 읽혔는가"는 Zeabur 보고서와 각 발급처의 사용 기록으로 판단해야 합니다.

Cremit Platform이 하는 일은 우리 회사 쪽입니다. 연결한 저장소와 공개 표면에서 노출된 자격증명을 찾고, 그 키가 지금도 발급처에서 유효한지 확인하고, AWS Secrets Manager·GCP Secret Manager·HashiCorp Vault 같은 저장소의 시크릿과 함께 한 인벤토리에 올립니다. 비공개 레포에 평문으로 들어간 클라우드 키, 만든 지 오래됐는데 여전히 인증되는 키, 같은 값이 여러 곳에 복사된 키가 그 인벤토리에서 보입니다. 사고가 났을 때 "공격자가 닿을 수 있었던 범위에 무엇이 있었나"에 답하려면 그 목록이 먼저 있어야 합니다.

교체 범위는 공격자가 닿을 수 있었던 곳까지

Zeabur는 8월 사고 뒤 확인된 키를 교체했고, 확인되지 않은 키는 그대로 두었습니다. 10월 공격자는 그 남은 키로 들어왔습니다. 서비스를 접는 이유는 하나가 아니었지만, 두 번째 사고를 만든 것은 교체 목록의 빈칸이었습니다.

사고 뒤 교체 범위는 유출이 확인된 키가 아니라, 공격자가 닿을 수 있었던 곳에 있던 모든 키로 잡으세요.

출처

함께 읽기

네트워크에 공유해보세요LinkedInX

이어서 읽기

다음 글을 메일로 받아보세요

Cremit의 월간 자격증명 보안 브리프. 한 통에 핵심만 담습니다.

이메일을 판매하거나 외부에 넘기지 않으며, 언제든 수신거부할 수 있습니다.