바이브코딩 앱 보안 체크리스트 — Supabase RLS 켜셨나요?
바이브코딩으로 뚝딱 만든 내 앱, 데이터베이스 보안은 누가 챙겼을까요? 2025년 AI 코딩 플랫폼 Lovable로 만든 앱 1,645개를 스캔했더니 170개(약 10.3%)가 로그인 없이도 데이터를 읽고 쓸 수 있는 상태였습니다(CVE-2025-48757, CVSS 9.3). 대부분 원인은 Supabase RLS(행 단위 보안) 설정 누락이었고, 지금 내 앱에도 똑같은 구멍이 있을 수 있어요.
무슨 일이 있었나 — 앱 1,645개 중 170개가 뚫렸다
보안 연구원 Matt Palmer가 2025년 3월 20~21일 이틀에 걸쳐 Lovable로 만들어진 공개 앱 1,645개를 직접 스캔했습니다. 결과는 예상보다 심각했어요. 170개, 전체의 약 10.3%가 Supabase RLS 정책이 제대로 걸려 있지 않아서 인증 절차 없이 데이터베이스 테이블을 읽고 쓸 수 있는 상태였습니다. 영향을 받은 엔드포인트만 303개였고요. 이 조사 결과는 2025년 5월 29일 CVE-2025-48757로 공식 등록됐고, MITRE·CNA는 이 취약점의 심각도를 10점 만점에 9.3점, 즉 ‘치명적(Critical)’ 등급으로 평가했습니다.
숫자만 보면 감이 잘 안 오니 표로 정리해볼게요.
| 구분 | 내용 |
|---|---|
| 스캔 대상 | Lovable로 만든 공개 앱 1,645개 |
| 취약 앱 | 170개(약 10.3%) |
| 영향받은 엔드포인트 | 303개 |
| 문제 원인 | Supabase RLS(행 단위 보안) 정책 미흡 — 공개 anon key만으로 인증 없이 테이블 읽기·쓰기 가능 |
| 발견·보고 | 2025년 3월 20~21일, 보안 연구원 Matt Palmer |
| CVE 공식 공개 | 2025년 5월 29일, CVE-2025-48757 |
| 심각도 | CVSS 9.3(Critical, MITRE/CNA 평가) |
이게 남 얘기가 아닌 게, Lovable 하나만의 문제가 아니라는 점이에요. Lovable이 쓰는 백엔드가 Supabase라서 이번 조사 대상이 됐을 뿐, Cursor·Claude Code 같은 다른 바이브코딩 도구로 Next.js+Supabase 조합을 쓰는 앱이라면 구조적으로 똑같은 위험을 안고 있습니다.

Supabase RLS가 뭐길래 이렇게 자주 빠질까
RLS는 Row Level Security, 우리말로 ‘행 단위 보안’입니다. 테이블 전체를 통째로 열어주는 대신 “이 사용자는 이 행까지만 볼 수 있다”는 규칙을 데이터베이스 레벨에서 강제하는 기능이에요. 문제는 이게 항상 켜져 있는 게 아니라는 거예요. Supabase 공식 문서에 따르면 SQL 편집기로 테이블을 직접 만들면 RLS는 기본적으로 꺼진 상태로 생성됩니다. 대시보드의 Table Editor로 테이블을 만들 때만 자동으로 켜지고요. 바이브코딩 도구가 AI에게 “테이블 만들어줘”라고 시키면 대개 SQL을 직접 실행하는 방식이라, 이 기본값 함정에 그대로 걸리기 쉽습니다.
왜 이게 치명적이냐면, Supabase의 anon key는 원래 클라이언트(브라우저)에 공개적으로 노출되도록 설계된 키거든요. 프런트엔드 코드나 배포 산출물만 열어봐도 누구나 이 키를 꺼내 쓸 수 있어요. RLS가 꺼진 테이블이라면 이 공개 키 하나로 로그인 절차 없이 테이블 전체를 조회하고, 심지어 수정·삭제까지 가능합니다. 인증이 아예 없는 게 아니라, ‘인증을 확인하는 문’ 자체가 없는 셈이죠.
저도 이 통계 보고 나서 얼마 전에 사이드 프로젝트로 만들어둔 바이브코딩 앱 하나를 다시 열어봤는데요, 테이블 하나에 RLS가 꺼진 채로 몇 주째 방치돼 있더라고요. 다행히 개인 메모용이라 큰일은 안 났지만, 회원 정보나 결제 내역이었으면 생각만 해도 아찔했습니다.
지금 바로 확인하는 RLS 체크리스트
이론은 이 정도면 됐고, 실제로 뭘 확인해야 하는지가 중요하겠죠. 아래 항목을 Supabase 대시보드나 SQL 편집기에서 하나씩 확인해보세요. 순서대로 훑으면 10분이면 충분합니다.
- 모든 public 테이블에 RLS가 켜져 있는지 — SQL 편집기에서
select tablename, rowsecurity from pg_tables where schemaname = 'public';를 실행해rowsecurity가 전부true인지 확인합니다. 하나라도false면 그 테이블은 지금 이 순간 공개 상태예요. - RLS를 켰다면 정책(policy)도 같이 있는지 — RLS만 켜고 정책을 안 만들면 기본값은 ‘전부 차단’이라 안전은 하지만 앱이 아예 안 돌아갑니다. 반대로
using (true)같은 느슨한 정책 하나만 걸어놓으면 RLS를 켰어도 사실상 무방비인 것도 확인해야 해요. - anon·authenticated·service_role 역할을 구분해서 정책을 짰는지 — anon은 비로그인 공개 키, authenticated는 로그인한 사용자, service_role은 서버 전용 관리자 키입니다. service_role 키가 프런트엔드 코드나 깃허브 저장소에 노출돼 있지 않은지도 함께 확인하세요.
- 본인 데이터만 접근되는지 직접 테스트해보기 — 브라우저 개발자 도구에서 anon key로 Supabase REST 엔드포인트를 직접 호출해서, 다른 사용자의 행까지 보이지는 않는지 실제로 시험해보는 게 가장 확실합니다.
- 새 테이블을 만들 때마다 습관처럼 RLS부터 켜기 — AI 코딩 도구는 이 부분을 알아서 챙겨주지 않습니다. 테이블 하나 추가할 때마다
alter table 테이블명 enable row level security;를 먼저 실행하는 걸 루틴으로 만드는 게 제일 확실해요.
이 다섯 개만 확인해도 이번 CVE의 원인이 됐던 ‘공개 anon key로 테이블 전체 접근’이라는 최악의 시나리오는 대부분 막을 수 있습니다.

이런 착각, 저도 처음엔 했어요
바이브코딩을 처음 시작하면 흔히 하는 오해가 몇 가지 있는 것 같아요. 가장 큰 건 “AI가 만들어줬으니 기본 보안도 알아서 챙겨줬겠지”라는 생각인데, 이번 사고가 정확히 그 반대를 보여줬습니다. AI 코딩 도구는 기능을 빠르게 구현해주는 데는 강하지만, 보안 기본값까지 알아서 안전하게 잡아주는 건 아니거든요.
또 하나는 “테이블 만들 때 딱 한 번만 RLS 켜면 끝”이라는 생각인데, 이것도 반은 맞고 반은 틀려요. 새 테이블을 추가하거나 컬럼을 바꿀 때마다 정책을 다시 점검해야 하니까요. (아 그리고 이건 여담인데, RLS를 켜놓고 정책을 안 만들어서 오히려 앱이 통째로 안 돌아가는 경우도 은근히 많더라고요 — 무조건 켜는 게 능사는 아니고, 켠 다음 제대로 된 정책까지 확인하는 게 세트예요.)
“플랫폼 책임 아니다” — Lovable 입장이 말해주는 것
흥미로운 지점은 CVE 공급자인 Lovable이 이 취약점 자체에 이의(dispute)를 제기했다는 거예요. 입장은 명확합니다. 플랫폼이 아니라 각 고객, 즉 개발자 본인이 자기 앱의 데이터 보호 정책을 설정할 책임이 있다는 거죠. 틀린 말은 아니에요 — 실제로 데이터베이스 보안 설정 권한은 개발자에게 있으니까요. 다만 이 입장이 바이브코딩 사용자에게 주는 메시지는 분명합니다. AI 코딩 도구가 안전한 기본값을 대신 보장해주지 않는다는 것, 그러니 RLS 같은 설정은 결국 내가 직접 확인해야 한다는 것.
지난번 챗GPT 구글드라이브 연결 글에서는 ‘AI에게 내 데이터 접근 권한을 넘길 때’의 위험을 다뤘는데요, 이번 건 방향이 조금 달라요. 이번엔 AI가 만들어준 앱 자체의 보안 설정을 내가 확인 안 하고 지나간 게 문제였거든요. 두 경우 다 결국 하나로 이어집니다. 편해졌다고 확인까지 AI에게 맡기면 안 된다는 거예요.
바이브코딩 자체를 겁낼 필요는 없다고 봐요. 다만 앱을 뚝딱 만든 뒤에 위 체크리스트 다섯 개만이라도 10분 투자해서 확인해보시길 권합니다. 지금 만들어둔 사이드 프로젝트, 오늘 한번 열어보시는 건 어떨까요.






