Vibecoded 앱을 감사할 때 계속 발견되는 문제들
요약
AI로 생성된 앱(Vibecoded)에서 반복적으로 발생하는 보안, SEO, 성능, 코드 품질 문제를 분석합니다. 특히 클라이언트 측 비밀 정보 노출, SPA의 SEO 이슈, 에러 경계 부재, 폼 검증 미비 등의 취약점을 경고합니다.
핵심 포인트
- 클라이언트 측에 API 키나 서비스 롤 키가 노출되는 보안 위험
- SPA 구조로 인한 동일한 메타 데이터 반환 및 SEO 색인 문제
- 에러 경계(Error Boundaries) 부재로 인한 앱 전체 충돌 위험
- 데이터 검증 및 정화(Sanitization)가 없는 취약한 폼 구현
똑같은 다섯 가지 문제가 계속해서 나타납니다. 보안, SEO, 성능, 접근성 및 코드 품질을 기준으로 AI 생성 앱의 점수를 매기는 우리의 도구인 Audit Vibe Coding을 통해 들어오는 모든 vibecoded 프로젝트 전반에 걸쳐, 특정 문제들이 너무나 예측 가능하게 반복되어 우리는 이를 추적하기 시작했습니다.
우리는 17개의 라이브 앱을 보유한 소프트웨어 스튜디오인 Inithouse에서 AI 제품을 만듭니다. 그중 대부분은 AI 도구로 스캐폴딩(scaffolding)되었습니다. 따라서 vibecoded 프로젝트를 위한 전용 감사 도구를 구축했을 때, 우리는 이미 앞서 나갈 수 있었습니다. 우리 자신의 코드에서도 이미 이러한 문제들을 발견했기 때문입니다.
계속해서 나타나는 문제들은 다음과 같습니다.
눈에 띄게 노출된 클라이언트 측 비밀 정보 (Client-side secrets)
이 문제는 거의 보편적입니다. AI는 Supabase 또는 Firebase 통합 코드를 생성하면서, anon key를 .env 파일에 넣거나, 더 심한 경우 소스 코드에 직접 집어넣습니다. 이 키는 브라우저로 전송됩니다. DevTools를 사용하는 사람이라면 누구나 이를 읽을 수 있습니다.
Row Level Security (RLS)가 올바르게 구성되어 있다면 anon key 자체는 치명적이지 않습니다. 하지만 대부분의 vibecoded 프로젝트에서는 이것이 구성되어 있지 않습니다. AI가 설정하지 않았고, 빌더(builder)는 요청해야 한다는 사실을 몰랐기 때문입니다. 우리는 service_role 키(데이터베이스 전체 액세스 권한)가 동일한 방식으로 노출된 프로젝트들도 보았습니다. 빌드된 JavaScript를 grep으로 한 번만 검색해 봐도 바로 나타납니다.
모든 페이지가 동일한 HTML title과 meta description을 반환함
이것은 전형적인 SPA (Single-Page Application) 렌더링 버그이며, vibecoded 앱에서 압도적으로 가장 흔한 SEO 이슈입니다. AI는 React 단일 페이지 애플리케이션을 스캐폴딩합니다. 라우터(router)는 브라우저에서 페이지 전환을 처리합니다. 하지만 Google이나 AI 크롤러가 URL을 요청하면, 서버는 모든 페이지에 대해 동일한 기본 HTML 셸(shell)을 반환합니다. 즉, 동일한 <title>, 동일한 meta description, 홈페이지를 가리키는 동일한 canonical tag를 반환하는 것입니다.
50개의 콘텐츠 페이지를 가진 프로젝트가 Google 인덱스에는 홈페이지의 거의 중복된 페이지 50개로 나타나게 됩니다. 우리는 정확히 이 이유로 인해 페이지의 70-80%가 "크롤링됨, 현재 색인 생성되지 않음"으로 표시된 크롤링 보고서를 본 적이 있습니다.
어디에도 에러 경계 (Error boundaries)가 없음
vibecoded React 컴포넌트가 에러를 발생시키면 앱 전체가 하얗게 변합니다. 폴백 UI (fallback UI), 에러 메시지, 복구 경로가 전혀 없습니다. AI는 사용자가 명시적으로 요청하지 않는 한 에러 경계 (error boundaries)를 거의 생성하지 않습니다. 그 결과, 단 한 번의 API 호출 실패나 누락된 데이터 필드만으로도 페이지 전체가 충돌하는 취약한 앱이 만들어집니다. 사용자는 빈 화면을 보고 떠나버립니다.
감사(audit) 과정에서 이는 코드 품질 문제로 나타나지만, 성능 및 리텐션 (retention)에 직접적인 영향을 미칩니다.
입력을 그대로 통과시키는 폼 (Forms)
AI가 생성한 폼은 양쪽 끝단(client/server)에서의 검증 (validation)이나 정화 (sanitization) 없이 데이터를 수집하여 데이터베이스나 API 엔드포인트 (endpoint)로 직접 전송하는 경향이 있습니다. 길이 제한도 없고, 서버 측 타입 체크 (type checking)도 없으며, 엔드포인트에 대한 속도 제한 (rate limiting)도 없습니다. 저희는 스로틀 (throttle)이 없어 연락처 폼이 분당 수백 번씩 동일한 메시지를 제출할 수 있는 프로젝트들을 감사한 적이 있습니다.
vibecoded 앱에서 백엔드(backend)는 대개 몇 개의 Supabase 엣지 함수 (edge functions)나 서버리스 라우트 (serverless routes)로 구성됩니다. AI는 안전하게 작동하도록 쓰는 것이 아니라, 작동하게끔 작성합니다.
최적화 없이 전체 해상도로 제공되는 이미지
AI는 소스 URL이 포함된 <img> 태그를 그냥 집어넣습니다. srcset, 지연 로딩 (lazy loading), 너비/높이 (width/height) 속성, WebP 또는 AVIF 변환 등이 전혀 없습니다. 모바일 연결 환경에서는 단 하나의 히어로 이미지 (hero image)가 초기 로딩 시간을 3~5초 더 늘릴 수 있습니다. 저희는 이를 성능 점수에 반영하지만, 이는 복합적인 문제를 일으킵니다. 낮은 코어 웹 바이탈 (Core Web Vitals)은 SEO 순위를 떨어뜨리고, 이는 트래픽 감소로 이어지며, 결과적으로 유료 고객 획득 비용을 더 비싸게 만듭니다.
해결책은 기계적입니다 (단 한 번의 이미지 최적화 작업). 하지만 AI에게 이를 요청(prompt)하지 않았기 때문에, 저희가 살펴보는 거의 모든 vibecoded 프로젝트에서 이 부분이 누락되어 있습니다.
왜 이러한 특정 문제들이 계속 반복되는가
패턴은 항상 동일합니다. AI는 해피 패스 (happy path, 정상적인 흐름)에서 작동하는 코드를 생성합니다. 제작자는 이를 로컬에서 테스트하고, 작동하는 것을 확인한 뒤 배포합니다. 저희가 지적하는 문제들은 전통적인 의미의 버그 (bug)가 아닙니다. 앱은 실행되고, 페이지는 로드되며, 폼은 제출됩니다. 이들은 "작동한다"와 "프로덕션 준비가 되었다 (production-ready)" 사이의 간극입니다.
보안 설정 (Security configuration), 서버 사이드 렌더링 (Server-side rendering), 에러 핸들링 (Error handling), 입력 유효성 검사 (Input validation), 에셋 최적화 (Asset optimization): 이것들은 AI가 요청 없이 스스로 추가하는 기능이 아닙니다. 이것들은 스캐폴딩 (Scaffolding)이 완료된 후에 이루어지는 작업이며, vibecoded 워크플로우에서는 이 단계가 종종 완전히 생략됩니다.
그것이 바로 Audit Vibe Coding이 포착하도록 설계된 간극입니다. 우리는 다섯 가지 카테고리에 걸쳐 각 프로젝트를 점수화하고, 특정 문제를 표시하며, 우선순위가 지정된 수정 사항을 반환하여 빌더가 무엇을 먼저 해결해야 하고 무엇을 나중에 해도 되는지 알 수 있게 합니다. 이 도구는 우리 스스로에게 필요했기 때문에 존재합니다. 우리는 Inithouse 포트폴리오의 모든 제품이 출시되기 전에 동일한 감사를 수행합니다.
만약 당신이 AI 도구로 무언가를 구축하고 있고 그 결과물을 감사(audit)하지 않았다면, 위의 문제들이 살펴보기 시작할 만한 합리적인 지점이 될 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기