무슨 일이 있었나
10월 21일, Railway는 권한 없는 제3자가 고객 환경 변수를 저장하는 시스템에 접근했으며, 그중 일부는 공격자가 복호화된 내용을 손에 넣었을 수 있다고 공개했습니다. Railway는 모든 배포를 일시 중단하고, 업스트림 제공업체에 키 폐기를 요청했으며, 모든 사용자에게 프라이빗 레지스트리 자격 증명을 포함한 환경 변수를 교체하라고 안내했습니다.
예비 보고서에는 더 자세한 내용이 담겨 있습니다:
- 공격은 10월 20일부터 10월 22일 새벽(UTC)까지 이어졌습니다. 시작은 빌드 인프라에서의 권한 상승 시도였습니다.
- 일부 변수가 유출됐을 가능성이 있는 워크스페이스는 최대 1.85%, 약 10만 개입니다. 키가 암호화된 방식 때문에 Railway는 영향받은 프로젝트에서 정확히 어떤 시크릿이 노출됐는지 아직 특정하지 못하고 있습니다.
- 공격자는 AI 제공업체 API 키와 플랫폼 API 키를 찾아다녔습니다. Railway는 환경 변수나 AI 키가 많은 워크스페이스를 고위험으로 분류합니다.
- Railway는 유출된 키로 발생한 AI 사용 요금은 환불해 줄 수 없다고 밝혔습니다. 해당 제공업체와 직접 해결해야 합니다.
TechCrunch 보도에 따르면 Railway는 이번 사고가 AI 추론 제공업체를 노린, 플랫폼 대상의 더 광범위한 공격 캠페인의 일부라고 보고 있습니다. 같은 주에 AI 코딩 도구 OpenCode도 해커들이 고객의 1% 이상에게서 API 키와 기타 시크릿을 탈취했다고 공개했습니다.
개발자가 표적이 되는 이유
탈취된 AI 키는 실제로 돈이 됩니다. 공격자는 접근 권한을 되팔거나 자신들의 작업에 여러분의 사용량을 써 버립니다. 연구자들은 이런 수법을 LLMjacking이라고 부릅니다. 호스팅 플랫폼은 이런 키를 효율적으로 수확할 수 있는 곳입니다. 수천 개의 앱이 OpenAI, Anthropic, Stripe, 데이터베이스 키를 한곳에 모아 두기 때문입니다.
Railway 보고서에는 불편한 사실이 하나 있습니다. 변수는 암호화되어 있었지만, 플랫폼은 빌드와 실행 중인 서비스에 주입하기 위해 이를 복호화할 수 있어야 합니다. 공격자가 적절한 내부 접근 권한을 얻자 저장 시 암호화는 아무런 방어가 되지 못했습니다. 이건 Railway만의 문제가 아닙니다. 여러분의 코드를 실행하는 호스트라면 어디든 시크릿을 읽을 수 있습니다.
그러니 물어야 할 질문은 ‘내 호스트는 안전한가?’가 아닙니다. ‘내일 호스트의 시크릿이 유출된다면 피해는 얼마나 크고, 얼마나 빨리 복구할 수 있는가?’입니다.
노출 여부를 확인하는 방법
이미 몇 가지를 ‘교체’했더라도 20분만 투자하세요.
1. 모든 시크릿을 목록으로 정리합니다. 스테이징과 프리뷰 환경을 포함해 프로젝트와 환경별로 변수 이름을 나열하세요. .env.example 파일이 있다면 좋은 출발점입니다:
grep -oE '^[A-Z0-9_]+' .env.example각 변수가 무엇에 접근할 수 있는지 적어 두세요. 데이터베이스, 결제 제공업체, AI 제공업체, 이메일, 스토리지 버킷, GitHub 토큰 등입니다.
2. AI 제공업체의 사용량과 청구 내역을 확인합니다. 10월 20일 이후 사용량 급증, 낯선 모델, 이상한 시간대의 요청이 있는지 살펴보세요. 악용이 가장 먼저 드러나기 쉬운 곳입니다.
3. 가지고 있는 감사 로그를 확인합니다. Railway는 특히 GitHub 감사 로그와 설치된 앱의 접근 권한, 그리고 Docker Hub 같은 레지스트리 로그를 검토하라고 권장합니다. 결제 제공업체의 API 로그와 데이터베이스 연결 로그도 함께 확인하세요.
4. 데이터베이스가 인터넷에서 접근 가능한지 확인합니다. Railway 보고서는 데이터베이스의 공용 네트워크 접근을 제거하라고 권장합니다. 유출된 연결 문자열이 누구나 접속할 수 있는 데이터베이스를 가리킨다면, 그 유출은 즉시 악용될 수 있습니다:
nc -zv your-db-host.example 5432 # "succeeded" from your laptop = publicly reachable5. 프런트엔드가 이미 무엇을 노출하고 있는지 확인합니다. 이런 침해 사고는 진짜 시크릿과 원래 공개되도록 설계된 값을 구분해야 한다는 점을 상기시켜 줍니다. JavaScript 번들에 포함되어 배포되는 키는 애초에 비밀이 아니었습니다.
프로덕션을 망가뜨리지 않고 교체하는 방법
급할 때 흔히 하는 실수는 기존 키를 먼저 폐기한 뒤, 앱이 오류를 뱉는 동안 허둥지둥 새 키를 배포하는 것입니다. 대신 이 순서대로 진행하세요:
- 제공업체에서 새 자격 증명(새 API 키, 새 데이터베이스 비밀번호, 새 웹훅 시크릿)을 만듭니다. 기존 것은 당분간 그대로 둡니다.
- 호스트에서 변수를 업데이트하고, 실행 중인 앱이 반영하도록 다시 배포합니다.
- 새 값으로 앱이 잘 동작하는지 확인합니다. 실제로 해당 서비스를 사용하는 엔드포인트를 호출해 보세요.
- 제공업체에서 기존 자격 증명을 폐기합니다.
- 기존 자격 증명이 정말 무효화됐는지 확인합니다. 예를 들어 그것으로 테스트 호출을 보내 실패하는지 확인하세요.
목록은 피해 범위가 큰 순서대로 처리하세요. 결제 키, 데이터베이스 자격 증명, 클라우드 및 스토리지 키, AI 제공업체 키, GitHub 및 레지스트리 토큰, 그리고 나머지 순입니다. Railway 자체 가이드는 10월 21일 이전에 설정된 변수에 초점을 맞추고 있으며, 후속 안내에서는 GitHub 재연결과 CLI 및 CI 자격 증명 재생성도 추가로 권하고 있습니다.
특별히 주의해야 할 시크릿도 있습니다:
- 세션 서명 또는 JWT 시크릿. 이를 바꾸면 모든 사용자가 로그아웃됩니다. 침해 이후라면 대개 감수할 만하지만, 가능하면 사용자에게 미리 알리세요.
- 웹훅 서명 시크릿. 수신 측과 발신 제공업체를 함께 업데이트하지 않으면 한동안 정상적인 이벤트까지 거부하게 됩니다.
- 데이터베이스 비밀번호. 플랫폼이 지원한다면 같은 권한을 가진 새 데이터베이스 사용자를 만들고, 앱을 전환한 뒤 기존 사용자를 삭제하세요. 비밀번호를 그 자리에서 바꾸는 것보다 깔끔합니다.
다음 침해의 고통을 줄이려면
호스트가 침해당하는 것을 막을 수는 없습니다. 하지만 유출된 시크릿의 가치를 떨어뜨릴 수는 있습니다.
키 권한을 최소화하세요. 제공업체가 지원한다면 제한된 키를 사용하세요. 체크아웃 세션 생성만 가능한 Stripe 제한 키는 전체 권한을 가진 시크릿 키보다 공격자에게 훨씬 쓸모가 없습니다.
지출 한도를 정하세요. 모든 AI 제공업체에 월 예산과 사용량 알림을 설정하세요. 수천만 원짜리 날벼락이 이메일 한 통으로 끝납니다.
환경을 분리하세요. 프로덕션 키를 스테이징이나 프리뷰 배포에서 재사용하지 마세요. 환경마다 별도의 자격 증명을 두면 한 곳이 유출돼도 다른 환경까지 넘어가지 않습니다.
데이터베이스는 비공개로 유지하세요. 플랫폼의 프라이빗 네트워킹을 사용하고, Supabase를 쓴다면 Row Level Security를 반드시 켜서 anon 키가 유출되더라도 테이블이 노출되지 않게 하세요.
접근 가능한 파일에 시크릿을 두지 마세요. 웹 루트에 배포된 .env 파일은 침해 사고가 없어도 그 자체로 유출됩니다.
지금 교체 런북을 작성해 두세요. 1단계에서 만든 목록, 위의 순서, 그리고 각 키를 어디서 관리하는지를 적어 두면 됩니다. 다음번에는 주말을 통째로 쓰는 대신 한 시간이면 교체가 끝납니다.
빠른 체크리스트
배포하는 모든 앱에 대해 점검하세요:
- 모든 환경의 모든 시크릿을 무엇에 접근할 수 있는지와 함께 목록으로 정리했다.
- 각 시크릿을 생성, 배포, 확인, 폐기 순서로 교체했다.
- 10월 20일 이후의 AI 제공업체 사용량과 청구 내역을 검토하고 지출 한도를 설정했다.
- GitHub, 레지스트리, 결제, 데이터베이스 로그를 확인했다.
- 데이터베이스가 인터넷에서 접근할 수 없다.
- 프로덕션과 스테이징이 서로 다른 키를 사용한다.
- 진짜 시크릿이 프런트엔드 코드에 포함되거나 웹에서 접근 가능한 파일에 들어 있지 않다.
핵심 정리
Railway는 신속하게 공개하고 교체를 독려하는 올바른 대응을 했습니다. 하지만 호스팅 및 개발자 플랫폼에서는 이런 일이 계속 일어납니다. 키가 모여 있는 곳이기 때문입니다. 침착하게 위기를 넘기는 개발자는 자신이 어떤 시크릿을 갖고 있는지 알고, 오후 한나절이면 모두 교체할 수 있는 사람들입니다.
정리하는 김에 앱이 외부에 무엇을 노출하고 있는지도 확인해 볼 만합니다. AppSafe는 실제 운영 중인 사이트를 스캔해 JavaScript 번들 속 API 키, 노출된 .env 및 .git 파일, 누락된 보안 헤더 같은 흔한 문제를 찾아내고 이해하기 쉬운 해결 방법을 알려 줍니다. AI로 만든 앱을 위한 출시 체크리스트에서는 그 밖의 기본 사항도 다룹니다.
모든 교체를 마쳤다면 무료 AppSafe 스캔을 실행해 다른 곳에서 새는 것이 없는지 확인하세요.
