Preflight logoPreflight

샘플 리포트

Preflight 리포트의 예시입니다. 가상의 노트·이미지 공유 SaaS 사례로, 실제 리포트는 입력한 스택과 기능에 맞춰 이와 같은 형태로 생성됩니다.

샘플 리포트의 가상 앱 맥락

스택
Next.js (App Router) + Supabase (Auth · Storage · Postgres) + Drizzle ORM, Vercel 배포
단계
출시 전
기능
인증/로그인사용자 데이터 격리파일 업로드

예시 데이터입니다. 실제 리포트는 인터뷰에서 입력한 스택과 기능에 맞춰 생성됩니다.

지금 당장 수정(2)

.env가 git 히스토리에 커밋된 적 있음
개발자 확인 필요확인됨

지금 .gitignore에 추가했어도 과거에 한 번이라도 커밋됐다면 history에 영원히 남습니다. 회수한 메모지를 누군가 사진으로 찍어뒀다면 막을 수 없는 것과 비슷합니다.

왜 중요한가
git log --all --full-history -- .env*에 결과가 있으면 평문 시크릿(Supabase service_role key, NextAuth secret 등)이 과거 커밋 어딘가에 살아있다는 뜻입니다. 리포 접근권을 가진 누구든 회수할 수 있고, 공개 리포면 자동화 봇에게 이미 스캔됐을 가능성이 큽니다.
영향: 유출된 키가 즉시 악용 가능하며, 회복하려면 모든 노출 키 회전 + git history rewrite가 필요합니다
수정 방향
(1) 노출된 모든 키를 즉시 회전(Supabase service_role·anon, NextAuth SECRET 등). (2) git history 정리는 BFG Repo-Cleaner 또는 git filter-repo로 — 단순 git rm은 history에 그대로 남습니다. (3) .gitignore에 .env*, *.local, *.pem 표준 패턴 추가. (4) 향후 secret manager(1Password CLI 등) 도입 검토.
git remote가 GitHub 공개 리포인가요, private 리포인가요? 공개라면 자동화 봇에게 이미 스캔됐을 가능성이 높아 회전이 더 시급합니다.
Supabase 테이블에 행 단위 보안(RLS)이 켜져 있지 않음
개발자 확인 필요확인됨

도서관에서 누구나 모든 회원의 대출 기록을 볼 수 있는 것과 같아서, 한 사용자가 다른 모든 사용자의 노트를 조회할 수 있습니다.

왜 중요한가
Supabase는 클라이언트가 직접 데이터베이스에 질의할 수 있는 구조라, Row Level Security를 켜지 않으면 anon key만 있어도 테이블 전체를 SELECT할 수 있습니다. 브라우저 콘솔에서 supabase-js 한 줄이면 끝납니다.
영향: 전 사용자의 노트 본문·제목·작성 시각이 비공개 설정과 무관하게 외부에 노출
수정 방향
사용자별 데이터가 들어간 모든 테이블에 RLS를 활성화하고, 자기 행만 읽고 쓸 수 있는 정책을 추가하세요. 활성화 직후 anon key로 SELECT가 막히는지 즉시 검증하세요.
현재 service_role key를 사용하는 백엔드 코드가 있나요? 그 경로는 RLS를 우회하므로 별도로 권한 체크가 필요합니다.

출시 전 수정(2)

이미지 업로드 시 파일 종류·크기 검증이 없음
에이전트 수정가능성 높음

택배를 X-ray 검사 없이 전부 받는 것과 같아서, 사용자가 이미지가 아닌 파일이나 거대한 파일을 올려도 그대로 저장됩니다.

왜 중요한가
업로드 Server Action이 MIME 타입과 파일 크기를 검증하지 않습니다. 악성 SVG에는 JavaScript가 들어갈 수 있어 stored XSS 경로가 되고, 크기 제한이 없으면 한 명의 공격자가 스토리지를 채워 비용을 폭발시키거나 DoS를 일으킬 수 있습니다.
영향: 스토리지 비용 폭발, stored XSS 가능성, 다른 사용자에게 악성 파일 제공
수정 방향
업로드 Server Action에서 MIME 타입을 화이트리스트로 검증하고, 파일 크기 상한을 두세요. SVG는 별도 sanitizer를 거치거나 아예 거부하세요.
현재 SVG 업로드를 허용하고 있나요? 허용한다면 DOMPurify 같은 서버사이드 sanitizer를 거치는지 확인이 필요합니다.
Supabase Auth의 Refresh Token Rotation 설정 미확인
대시보드 확인불확실

갱신 토큰이 회전되지 않으면 한 번 유출된 토큰으로 공격자가 무기한 세션을 유지할 수 있습니다. 만료된 호텔 카드키가 영원히 작동하는 것과 같습니다.

왜 중요한가
Supabase Auth는 Refresh Token Rotation을 옵션으로 제공하며 프로젝트 생성 시점에 따라 기본값이 다릅니다. 회전이 켜지면 사용된 refresh token이 즉시 무효화돼 유출 시 공격 창이 짧아집니다. 이 설정은 코드만 봐서는 확인할 수 없고, 대시보드에서 직접 확인해야 합니다.
영향: 갱신 토큰이 유출될 경우 공격자가 사실상 무기한으로 사용자 세션을 유지하며 계정 데이터에 접근
수정 방향
Supabase 대시보드의 Authentication 설정에서 Refresh Token Rotation 옵션을 확인하고, 비활성화돼 있다면 켜세요. Reuse interval은 네트워크 재시도를 감안해 짧게(10초 이하) 두는 것을 권장합니다.
현재 운영 중인 활성 세션이 많다면, 회전을 켜는 시점에 일부 세션이 강제 로그아웃될 수 있습니다. 적용 시점과 사용자 안내를 어떻게 잡을지 함께 설계할까요?
확인 가이드
**어디로 가나요** Supabase 대시보드 → 프로젝트 선택 → Authentication → Settings → Auth → "Refresh Token Rotation" 섹션 **무엇을 확인하나요** - "Enable refresh token rotation": 현재 OFF → 권장 ON - "Reuse interval": 현재 값 → 권장 10초 이하 (네트워크 재시도 허용 폭) **문제가 있다면** 1. "Enable refresh token rotation" 토글을 ON으로 변경 2. Reuse interval을 10초로 설정 3. 페이지 하단의 "Save" 버튼 클릭 4. 변경 후 "Settings updated" 토스트 확인 **확인 후 테스트** 1. 시크릿 모드에서 로그인 → 개발자 도구 Network 탭에서 /token 응답의 refresh_token 복사 2. 동일한 refresh_token으로 /token POST를 2회 연속 호출 → 두 번째 호출이 401로 거부되면 회전이 적용된 것 3. 정상 흐름에서는 매 갱신마다 새 refresh_token이 발급되므로 일반 사용자 세션은 영향 없음

불확실 — 전문가 검토 권장(1)

환경 변수 노출 범위를 코드만으로 확인할 수 없음
개발자 확인 필요불확실

금고 비밀번호가 적힌 메모를 어디에 두었는지 파악이 안 되는 상황과 같아서, service_role key가 클라이언트 번들에 섞여 들어갔는지 확신할 수 없습니다.

왜 중요한가
Next.js는 NEXT_PUBLIC_ 접두사가 붙은 환경 변수만 클라이언트에 노출하지만, 실수로 일반 변수를 클라이언트 컴포넌트에서 import하면 빌드 결과물에 포함될 수 있습니다. service_role key가 노출되면 RLS를 우회해 데이터베이스 전체를 조작할 수 있습니다.
영향: 최악의 경우 데이터베이스 전체 조회·수정 권한이 외부에 유출
수정 방향
빌드 결과물에서 service_role key의 일부 문자열을 grep으로 검색해 직접 확인하세요. 그리고 service_role key를 쓰는 모든 코드 경로가 Server Action 또는 Route Handler에 한정돼 있는지 점검하세요.
현재 어떤 파일에서 service_role key를 사용하고 있나요? 그 파일이 클라이언트 컴포넌트에서 import되지 않는지 확인이 필요합니다.

나중에 개선(1)

민감 작업에 대한 감사 로그가 없음
에이전트 수정확인됨

CCTV가 없는 매장처럼, 보안 사고가 났을 때 누가 무엇을 했는지 추적할 방법이 없습니다.