← 전체 글

보안

16,326개의 Supabase 데이터베이스를 누구나 읽을 수 있다. 공통점은 에이전트가 만든 테이블이다

UpGuard는 공개 인터넷에서 누구나 테이블을 읽을 수 있는 Supabase 기반 데이터베이스 16,326개를 찾아냈고, 그중 절반 이상에 개인정보가 들어 있었다. 침해는 없었다. 노출의 원인은 사람이 지나는 경로가 아니라 코딩 에이전트가 지나는 경로에 적용되는 기본 설정이다.

MAI
어두운 배경의 Supabase 공식 문서 카드. 제목은 'Row Level Security', 설명은 'Secure your data using Postgres Row Level Security', 그리고 Supabase 로고가 함께 표시되어 있다.

보안 기업 UpGuard가 9월 25일, 공개 인터넷에서 누구나 테이블을 읽을 수 있는 Supabase 기반 데이터베이스 16,326개를 확인했다는 조사 결과를 공개했다. 그중 절반 이상에는 실재하는 사람들의 개인정보가 들어 있다. 이름, 생년월일, 이메일 주소, 전화번호, 주소. 그보다 적은 수의 데이터베이스에는 평문 비밀번호와 인증 토큰이 들어 있었다.

침입은 없었다. 취약점도, 패치도, CVE도 없다. 이 데이터베이스들은 모두 자신의 설정이 지시하는 그대로 정확히 동작하고 있다. 이 사안이 또 하나의 유출 사건과 다른 이유가 바로 그것이다. 실패는 구조적이며, 그것은 기본 설정이다.

문제의 중심에 있는 설정

Supabase는 모든 프로젝트에 호스팅형 Postgres 데이터베이스와 그 앞단의 REST 인터페이스를 제공한다. 방문자의 브라우저에서 실행되는 클라이언트 측 코드에는 Supabase가 anon 키라고 부르는 키가 담긴다. 이 키는 공개되는 것을 전제로 한다. 프로젝트를 식별하는 것 이상의 역할은 없으며, Supabase 문서도 그렇게 설명하고 있다.

이 공개 키가 마스터 키처럼 작동하지 않도록 막아 주는 것이 행 수준 보안(RLS)이다. 특정 역할이 어떤 행을 볼 수 있는지 결정하는 Postgres 기능이다. RLS가 켜져 있고 정책이 작성되어 있으면 익명 방문자는 정책이 허용한 범위만 볼 수 있다. RLS가 꺼져 있으면 공개 스키마의 테이블은 요청하는 누구에게나 읽힌다. Supabase 자체 문서가 이 점을 분명히 밝히고 있다.

UpGuard의 주장은 이 구조의 두 축이 서로 어긋났다는 것이다. Supabase는 Table Editor 인터페이스로 만든 테이블에 대해서는 RLS를 기본으로 켠다. 그러나 API를 통해 프로그램적으로 만든 테이블은 같은 기본값을 물려받지 않는다. 그리고 프로그램적 생성이야말로 코딩 에이전트가 스키마를 구축하는 방식이다.

"Supabase는 지금, 안전하지 않은 설정 패턴이 구조적인 데이터 노출로 이어질 만큼 대규모로 보급된 국면에 있다"고 보고서 작성자이자 UpGuard의 리서치·인사이트 담당 디렉터인 Greg Pollock은 적었다.

실제로 담겨 있는 것

UpGuard는 Supabase 사용 흔적이 있는 약 30만 개 도메인을 분석했으며, 데이터베이스 전체를 읽지 않고 데이터 유형만 평가했다고 밝혔다. 보고서가 거명한 사례들은 기술 스택 외에는 공통점이 없다.

운영 주체노출된 내용
필리핀의 SIM 팜 조직2,000개 이상의 사용자 계정과 10만 건 이상의 SMS 메시지
미국의 발레파킹 업체10만 명 이상의 고객, 차량 번호판과 방문 이력 포함
인도 기반 플랫폼65,467명분, 사적인 대화 포함
캐나다의 이주 지원 서비스약 5,000건의 기록, 자격증명 포함
한 아프리카 국가의 주프랑스 영사관신청자 기록

SIM 팜과 영사관은 같은 종류의 조직이 아니다. 마주하는 공격자도 다르고, 무엇을 비밀로 여기는지에 대한 감각도 다르다. 그런데도 같은 실수를 저질렀다. 그 이유에 대한 Pollock의 정리는 보고서에서 가장 날카로운 한 줄이다.

"보안 설정이 업종에 따라 달라지지 않는 것은, 사람들이 …… 자기 데이터베이스의 구성을 이해하지 못하기 때문이다."

AI와 관련된 대목

이 사안을 개발자의 부주의로 분류하고 넘어가고 싶어진다. 그러나 더 쓸모 있는 독해는 지금 누가 — 혹은 무엇이 — 스키마를 작성하고 있는가에 관한 것이다.

앱을 만들라는 지시를 받은 AI 코딩 에이전트는 API를 통해 테이블을 만든다. 그것이 에이전트에게 주어진 인터페이스이기 때문이다. 그리고 클라이언트에 anon 키를 연결한다. 문서가 그렇게 하라고 적혀 있기 때문이다. 두 단계 모두 그 자체로는 옳다. 일어나지 않는 단계는 애초에 프롬프트에 없던 단계다. 즉 테이블마다 "이것을 누가 읽을 수 있어야 하는가"를 판단하는 일이다. 같은 앱을 대시보드에서 사람이 만들었다면 안전한 기본값을 받았을 것이다. 기계는 다른 경로로 간다.

이것은 지금 도래하고 있는 문제군 전체의 형태다. 보안 기본값은 사람이 콘솔 앞에 앉아 경고를 보고 무언가를 클릭한다는 전제 위에 설계되었다. 에이전트는 콘솔 앞에 앉지 않는다. 안전한 기본값이 데이터베이스가 아니라 UI에 있을 때, 자동화는 그것을 우회한다. 그것도 자동화가 작동하는 속도와 규모로.

Supabase의 입장

Supabase의 최고정보보안책임자 Bil Harmer는 TechCrunch에 "우리 프로젝트는 기본적으로 안전하다"고 말하며 보안은 회사와 고객의 공동 책임이라고 설명했다. 그는 "우리는 이를 제대로 해내는 데 깊이 신경 쓰고 있으며, 모든 개발자가 더 안전하게 출시할 수 있도록 계속 개선해 나갈 것"이라고 덧붙였다.

두 가지는 동시에 참일 수 있다. Supabase가 사람을 위해 설계한 경로에서는 기본값이 건전하다. 노출이 일어나는 곳은 기계가 지나는 경로이며, 16,326개라는 숫자는 '사용자 교육의 문제'라고 부르고 넘어갈 수 있는 수치가 아니다.

그중 하나를 운영하고 있다면

확인할 것은 공개 스키마의 모든 테이블에서 RLS가 켜져 있는지 여부다. Supabase 문서는 RLS를 켜는 것만으로는 충분하지 않다고 분명히 밝히고 있다. anon과 authenticated 역할에 자동으로 부여되는 권한도 함께 회수해야 한다. 보호되지 않은 테이블은 프로젝트 대시보드에 경고로 표시되며, 그 목록이 출발점이다.

아무도 만든 기억이 없는 테이블부터 보라. 현재까지의 증거에 비추어 보면, 그것이 바로 에이전트가 만든 테이블이다.

UpGuard는 조사 과정에서 확인한 중대한 노출에 대해 소유자들에게 통지했다고 밝혔다. 그 테이블에 이름과 주소와 비밀번호가 실린 사람들에게는, 그 통지가 그들이 가질 수 있었던 유일한 통제 수단이었다.

Sources: UpGuard — Everything, Everywhere: Systemic Data Exposure in Supabase Apps · TechCrunch — Some Supabase customers are publicly exposing reams of people's data to the web · Supabase documentation — Row Level Security · Unite.AI — UpGuard Study Finds 16,326 Supabase Databases Exposing Readable Tables

이어서 읽기