Vercel이 100만 달러를 걸고 진행한 Sandbox 챌린지에 취약점 제보 1,285건이 접수됐습니다. 이 과정에서 리눅스 커널 제로데이 취약점이 발견됐고, 버그 바운티로 총 24만 2,000달러가 지급됐습니다.
지난 8월 Vercel은 보안 연구자들이 Vercel Sandbox를 탈출해 보도록 100만 달러 규모의 해커 챌린지를 열었습니다. 사이버 보안 전문 기업 Trail of Bits와도 협력해 소스 코드와 보안 아키텍처를 검토했습니다.
챌린지 결과를 요약하면 다음과 같습니다.
2주 동안 접수된 제보 1,285건
지급된 버그 바운티 24만 2,000달러
발견된 리눅스 커널 제로데이 취약점 1건
Vercel Sandbox에서 고객 데이터에 접근했다는 제보는 한 건도 없었습니다. 가장 심각한 발견은 업스트림 리눅스 커널의 결함이었습니다.
이번 프로그램에서 가장 중요한 제보는 사흘째에 들어왔습니다.
HackerOne 연구자 Paulos Yibelo(pwn.ai)는 특별한 권한이 없는 일반 샌드박스 환경에서 리눅스 커널 네트워킹 스택의 결함을 찾아냈습니다. Paulos는 microVM 내부에서 특수하게 조작한 패킷을 보내면 세 가지 공격이 가능하다는 사실을 확인했습니다.
네트워크를 통한 호스트 메모리 유출
호스트 머신 크래시
호스트에서 코드 실행
첫 번째 공격에서는 호스트의 메모리가 게스트가 인터넷으로 보내는 패킷에 섞여 나옵니다. 호스트는 내 샌드박스가 다른 테넌트와 함께 쓰는 머신입니다. 게스트가 패킷을 계속 보내는 한 이런 유출이 지속될 수 있습니다.
이 공격은 Vercel 프로덕션 샌드박스를 대상으로 시연됐습니다.
연구자는 특정 패킷을 보내 호스트를 장악할 수도 있다는 사실을 발견했습니다.
먼저 패킷 두 개만으로 호스트 머신을 크래시시켜, 그 위에서 돌아가던 모든 샌드박스를 종료시켰습니다. 또 같은 결함을 이용해 호스트에서 전체 관리자 권한으로 명령을 실행했고, 샌드박스의 격리 경계를 벗어났습니다.
패킷을 이용한 크래시와 코드 실행 공격은 Vercel Sandbox 구성과 동일하게 맞춘 연구자 본인의 KVM 및 Firecracker 머신에서 시연됐습니다.
주요 클라우드 제공업체는 대부분 리눅스 커널의 이 같은 계층에서 고객 워크로드를 격리합니다. 따라서 이 계층의 결함은 공유 인프라 전체의 위험으로 이어집니다.
Vercel은 제보를 받자마자 연구자와 협력해 취약점을 파악하고 완화했습니다. AWS 등 업계 파트너와 함께 수정을 우선 처리하며 Vercel 고객과 해당 커널을 쓰는 다른 개발자들의 안전을 확보했습니다.
연구자도 커널 메인테이너에게 직접 연락해 패치 후보를 함께 만들었습니다. 수정 사항은 비공개로 검토 중이고 CVE도 아직 발급 전이므로, 패치가 공개되기 전까지는 세부 내용을 밝히지 않습니다. 취약점의 존재만 알리는 이유는 이미 다른 경로로 공개됐기 때문입니다.
HackerOne 챌린지는 모든 연구자에게 바운티를 열어 두었지만, Vercel은 여기에 내부 평가와 독립 조사까지 더했습니다.
공개 바운티를 시작하기 전에 소스 코드 전체에 접근할 수 있는 상태에서, Vercel Sandbox를 만들고 운영하는 엔지니어들의 지원을 받아 라이브 환경에서 내부 보안 평가를 진행했습니다. 또 Trail of Bits에서 엔지니어 두 명을 투입해 보안 아키텍처를 평가하도록 했습니다.
외부에서만 취약점이 나온 것은 아닙니다. Vercel 인턴 Marcos Hernanez는 리눅스 device-mapper 스토리지 계층에서 테넌트 간 데이터 유출 취약점을 찾아냈습니다. 이 취약점 때문에 어떤 샌드박스든 이미 삭제된 다른 샌드박스가 쓰던 디스크 블록을 재활용해 읽을 수 있었습니다.
Trail of Bits는 저장소 전체와 엔터프라이즈 테스트 팀 두 곳에 대한 접근 권한을 받아 엔지니어 4주 분량의 시간을 들여 소스 코드를 분석했습니다. 그 결과 20건의 발견 사항을 전달했고, 모두 테스트와 확인을 거쳐 해당 코드 위치까지 명시했습니다.
아키텍처 검토도 함께 진행해 Vercel의 가상화 경계가 견고하다고 결론 내렸습니다. 샌드박스는 각각 전용 게스트 커널을 가진 독립된 Firecracker microVM에서 실행되며, 디바이스 모델도 의도적으로 최소한으로 유지합니다. 어떤 게스트도 실행 중인 커널을 호스트나 다른 테넌트와 공유하지 않습니다.
Trail of Bits는 이 기반 위에서 세 가지 구조적 개선안을 권고했고, Vercel은 이를 모두 반영했습니다.
게스트에 대한 신뢰를 모두 찾아 없앤다. 기존 컨트롤 플레인은 microVM 내부 소프트웨어가 반환한 값을 그대로 받아들였는데, 이런 값은 모두 테넌트가 입력한 값입니다. 경계를 넘어오는 값은 서버 측에서 직접 도출하거나, 게스트가 접근할 수 없는 키로 서명해야 합니다.
정책은 하나, 판단 주체도 하나. 이그레스 제어가 여러 서브시스템에 나뉘어 있었고, 각 서브시스템이 같은 네트워크 정책을 따로 파싱하다 보니 판단이 엇갈릴 때가 있었습니다. 이제는 데이터 유형별로 정규화 루틴을 하나만 두고, 판단은 컴포넌트 하나가 맡으며, 정책이 바뀌면 연결을 다시 검증합니다.
다음 제로데이가 나온다고 가정한다. 공격자가 가상화 소프트웨어의 취약점을 악용하더라도 피해를 최소화하도록 각 샌드박스의 보호 장치를 강화했습니다. 호스트 커널은 항상 최신 상태로 유지하고, 중첩 가상화는 비활성화했습니다. 또 Firecracker의 jailer로 각 microVM 프로세스를 제한된 권한으로 실행하고 나머지 호스트와 분리합니다.
2주 동안 1,285건의 제보가 들어왔습니다. 연구자들이 이제 AI의 속도로 취약점을 찾기 때문에 가능한 규모입니다.
제보를 유형별로 나누면 다음과 같습니다.
중복 877건
해당 없음 319건
유효 57건
참고 32건
제보를 분류하는 과정에서 확인된 유효 건수는 다음과 같습니다.
Critical 1건
High 5건
Medium 9건
Low 42건
Informative 32건
지금까지 지급한 버그 바운티는 총 24만 2,000달러입니다.
Medium, Low, Informative 등급의 발견은 대부분 정책 경계의 사소한 허점입니다. 문서와 다르게 동작한 방화벽 규칙이나, 게스트를 필요 이상으로 신뢰한 필드 등이 그런 예입니다.
가장 심각한 발견은 리눅스 커널 제로데이 결함이었고, 고객의 파일이나 시크릿, 애플리케이션 데이터를 읽었다는 제보는 없었습니다.
가장 인상적이었던 점은 제보의 다양성입니다. 연구자마다 환경 구성도, 집중하는 분야도 달랐습니다. 리눅스 네임스페이스를 잘 아는 연구자는 에이전트를 커널 경계로 곧장 보냈고, 네트워크 정책을 파고든 사람도 있었습니다. 또 Vercel이 미처 대상으로 생각하지 못한 영역을 공략한 제보도 많았습니다.
공개 챌린지에 투자하는 가치는 바로 이런 다양성에 있습니다. 이번 챌린지에서 나온 흥미로운 발견 중 하나를 소개합니다.
챌린지 첫날 접수된 이 제보는 내부 평가와 화이트박스 점검을 거치고도 공개 버그 바운티를 운영해야 하는 이유를 가장 잘 보여주는 사례입니다.
샌드박스의 스냅샷을 만들면 컨트롤 플레인은 스냅샷 데이터가 어디에 저장됐는지 기록해야 합니다: {storage_url, size, checksum}. 연구자가 찾아낸 결함은 미묘했습니다. 이 저장 위치 정보가 게스트 내부에서 실행되는 소프트웨어에서 나왔는데도, 호스트에서 돌아가는 서비스가 이를 그대로 신뢰했던 것입니다. 이는 신뢰 경계 위반입니다. 게스트는 고객(그리고 해커)이 신뢰할 수 없는 코드를 실행하는 곳이므로, 호스트는 게스트의 말을 결코 권위 있는 정보로 받아들여서는 안 됩니다.
연구자는 이미 알려져 문서화된 컨테이너 탈출 기법에 이 신뢰 결함을 결합했습니다. 자신의 샌드박스 안에서 스냅샷 응답을 가로채 값을 바꿔치기해, 본인이 가진 서로 다른 두 계정의 스냅샷이 가리키는 스토리지 객체를 맞바꿨습니다. 그 결과 "내" 스냅샷을 복원하면 다른 계정의 파일 시스템 전체가 그대로 나타났습니다.
연구자는 두 계정이 서로의 파일을 읽고 수정할 수 있음을 시연하고 해시로 결과를 검증했습니다. 또 Vercel이 독립적으로 재현할 수 있도록 테스트 리소스도 그대로 보존했습니다.
이 공격에는 중요한 제약이 있습니다. 특정 피해자를 노려 바꿔치기하려면 그 피해자의 내부 스냅샷 스토리지 키를 알아야 합니다. 이 키는 플랫폼이 스냅샷마다 생성하는 무작위 96비트 식별자로, API로는 절대 노출되지 않습니다. 이 키가 나타나는 곳은 피해자 본인의 샌드박스 내부뿐입니다. 연구자가 두 계정을 모두 소유했기에 증명이 가능했던 것이고, 제3자가 다른 테넌트를 공격할 수 있는 경로는 입증되지 않았습니다. 그래도 Vercel은 이 건을 우선 수정 대상으로 다뤘습니다. 비밀이 지켜져야만 유지되는 경계는 경계라고 할 수 없기 때문입니다.
Trail of Bits도 평가 과정에서 같은 근본 원인을 독립적으로 지적했습니다. 완전히 다른 두 방향에서 발견됐다는 점이 이 문제가 실재하고 중요하다는 사실을 보여줍니다.
수정은 일주일 안에 배포됐습니다. 이제 컨트롤 플레인은 모든 스냅샷 객체를 그것을 생성한 프로젝트에 묶고, 그 외의 요청은 거부합니다. 스냅샷 생성은 게스트가 접근할 수 있는 환경에서 호스트 측 서비스로 옮겼고, 스토리지 경로는 프로젝트 단위로 구분하며 URL도 엄격하게 검증합니다.
제로데이든 중복 제보든, 제보해 주신 모든 연구자께 감사드립니다. 챌린지에서 발견된 모든 기법은 Vercel Sandbox에서 실행되는 워크로드를 보호하는 방법을 개선하는 데 쓰입니다.
포괄적인 내부 조사와 조언을 제공해 준 Trail of Bits에도 감사드립니다.