바이브코딩으로 만든 다이어리 앱, 얼마나 안전할까?
서론
요즘은 AI에게 "앱 하나 만들어줘"라고 말하는 것만으로도 누구나 그럴듯한 애플리케이션을 만들 수 있게 되었습니다. X에서 "바이브코딩"이라는 단어만 검색해봐도 개발 팁, 비개발자의 앱 제작 후기, 출시 사례를 쉽게 찾아볼 수 있습니다. 아이디어만 있으면 AI와 대화하며 기능을 붙이고, 화면을 만들고, 앱스토어에 출시하는 일이 더는 낯설지 않습니다.
그런데 과연, 바이브코딩으로 만든 애플리케이션은 얼마나 안전할까요?
지금부터 할 이야기는 "바이브코딩은 위험하니 쓰지 말자"는 이야기가 아닙니다. 오히려 이번 실험에서 AI는 보안 분석 도구로서는 꽤 강력했습니다. 이미 만들어진 코드를 보여주고 "이 코드에 어떤 취약점이 있는지 분석해봐”라고 물으면, 짧은 시간 안에 핵심 문제를 정확히 짚어냈습니다.
그런데 흥미로운 지점은 여기서 시작됩니다. 같은 AI에게 보안 요구사항 없이 "이런 기능의 앱을 만들어줘"라고만 하면, 방금 스스로 취약점이라고 짚어낼 법한 코드를 그대로 짜냅니다. 코드를 분석해서 문제를 찾아내는 능력과, 처음부터 그 문제를 피해서 코드를 작성하는 능력은 전혀 다른 문제라는 뜻입니다. 그 간극을 개인용 다이어리 겸 습관 트래커 앱 하나를 직접 만들어 확인해보겠습니다.
애플리케이션 바이브코딩
다이어리, 개인 습관 관리 앱들은 바이브코딩 예제로 자주 등장하는 주제입니다. 일기, 습관 기록, 사진 첨부, 알림, 공유처럼 기능 자체는 단순해 보이지만, 사용자의 사적인 데이터를 다룬다는 점에서 보안적으로 확인할 지점이 많습니다.
Codex에게 다이어리와 습관 트래커 기능을 가진 Android 앱 제작을 요청했습니다. 보안과 관련한 언급은 일부러 하지 않고, 회원가입, 로그인, 일기 저장, 습관 체크, 사진 첨부, PIN 잠금, 공유, 백업, 알림 등 기능 구현 중심의 프롬프트 하나만 제공했습니다.
위 화면들이 그렇게 만들어진 결과물입니다. 단 하나의 프롬프트만으로 기능적으로 꽤 그럴듯한 결과물이 나왔습니다.(물론 UI가 그다지 예쁜 편은 아니지만요)
당연히 이 앱에는 단 한 번의 프롬프트로 만들어졌다는 한계가 있습니다. 완성도나 안정성 측면에서 부족한 부분이 있는 게 이상한 일은 아닙니다. 이번 실험에서 정말 눈여겨봐야 할 부분은 "취약점이 있었다"는 사실 자체가 아니라, 그 취약점의 수준입니다.
분석
분석에는 복잡한 리버싱이나 고급 익스플로잇이 필요하지 않았습니다. adb, run-as, logcat, jadx 정도의 기본 도구만 사용했고, 확인한 항목도 모바일 앱 보안 점검에서 가장 먼저 보는 것들이었습니다.
분석 결과, 총 12개의 보안 문제를 확인했습니다. 그중 영향이 크면서도 가장 기본적인 5개만 보겠습니다.
1. 로컬 평문 저장 + 백업 추출 가능성
가장 먼저 확인된 문제는 앱의 핵심 데이터가 암호화 없이 SharedPreferences에 저장된다는 점입니다. 실제 단말에서 앱 내부 저장소를 확인해보면, 이메일, 로그인 세션, 습관 이름, 일기 내용, PIN 해시, 사진 경로가 모두 habit_diary_store.xml에 그대로 들어 있었습니다.
<string name="accountHash">8616976d6509ed6cb509a2cf1a29c124db662264cd734115bd4fd2c6c1c68e64</string>
<string name="sessionEmail">test@example.com</string>
<string name="pinHash">be544cdba4a755e5dc01269ca1ca654837dab39f7b17caf744de53b7d8c17de9</string>
<string name="diaries">[{"date":"2026-07-21","text":"test_diary1","photoPaths":[]}]</string>
이 앱은 개인용 다이어리와 습관 기록 앱이므로, 일기 내용 자체가 민감정보입니다. 건강 상태, 감정 상태, 일정, 인간관계 같은 내용을 기록한다면 이 데이터는 단순 설정값이 아니라 개인정보에 가깝습니다.
더 큰 문제는 백업 설정입니다. Manifest에는 백업이 허용되어 있고, 백업 규칙에는 SharedPreferences와 첨부파일 디렉터리가 그대로 포함되어 있습니다.
android:allowBackup="true"
<include domain="sharedpref" path="." />
<include domain="file" path="attachments/" />
이대로 배포되면, 단말 백업·기기 이전·루팅 환경 등을 통해 민감한 일기 데이터와 사진 경로가 추출될 수 있습니다. 사용자는 "앱 잠금이 있으니 안전하다"고 생각하지만, 정작 데이터 자체는 암호화되지 않은 채 그대로 보관되고 있는 셈입니다.
2. PIN·계정 비밀번호 약한 해시 저장
앱 잠금용 4자리 PIN은 평문 그대로 저장되지는 않았지만, 단순 SHA-256 해시로 저장되고 있었습니다.
fun setPin(pin: String): Result<Unit> {
prefs.edit().putString("pinHash", hash(pin)).apply()
}
fun verifyPin(pin: String): Boolean =
prefs.getString("pinHash", null) == hash(pin)
4자리 PIN은 경우의 수가 0000부터 9999까지 총 10,000개뿐입니다. 해시값을 확보하면 짧은 시간 안에 전수 대입 공격이 가능하고, 실제 테스트에서도 저장된 pinHash를 이용해 빠르게 원본 PIN을 찾아냈습니다.
계정 비밀번호도 같은 방식으로 저장됩니다.
.putString("accountHash", hash(password))
계정 비밀번호와 PIN 모두 salt가 없고, PBKDF2·bcrypt·Argon2 같은 느린 KDF도 쓰지 않습니다. "habit-diary:"라는 고정 문자열은 salt처럼 보일 수 있지만, 모든 사용자에게 동일하게 적용되는 값이라 APK를 디컴파일하면 바로 드러나는 사실상 무의미한 값입니다.
이대로 배포되면 공격자가 로컬 저장소나 백업 파일에서 pinHash, accountHash를 확보한 뒤 오프라인으로 대입 공격을 할 수 있습니다. 1234, 0000, password123처럼 흔한 값을 쓰는 사용자는 즉시 뚫립니다.
3. 앱 잠금 우회 및 PIN 제거 가능
앱에는 PIN 잠금 화면이 있었지만, 실제 보안 경계로 동작하지는 않았습니다. 로그아웃 후 다시 로그인하면 PIN 잠금이 우회되는 흐름이 확인됐습니다.
원인은 상태 관리 로직에 있습니다. logout()은 세션 이메일만 삭제할 뿐, PIN 해시와 일기·습관·계정 정보는 그대로 남겨둡니다.
fun logout() {
prefs.edit().remove("sessionEmail").apply()
}
동시에 UI 쪽 잠금 해제 상태(unlocked)가 메모리 값으로만 관리되어, 한 번 해제된 뒤에는 로그아웃해도 명확히 초기화되지 않습니다. 그 결과 재로그인 시 PIN 화면을 거치지 않고 바로 홈으로 진입하는 흐름이 발생합니다.
여기에 더해, 로그인 비밀번호만 맞으면 PIN을 삭제할 수 있는 재설정 로직도 있었습니다.
if (prefs.getString("accountHash", null) == hash(password)) {
prefs.edit().remove("pinHash").apply()
}
앞서 본 것처럼 계정 비밀번호 해시도 약하게 저장되어 있으므로, accountHash가 노출되면 PIN 보호까지 함께 무너집니다. PIN·비밀번호·생체인증이 겹겹이 있는 것처럼 보여도, 실제로는 가장 약한 고리 하나로 전체가 뚫리는 구조입니다.
4. Release APK 디버그 서명 + 무결성 방어 전무
Release 빌드 설정에서도 문제가 확인됐습니다. release APK인데도 debug signing config를 사용하고, minify·난독화도 꺼져 있습니다. 이 때문에 JADX로 APK를 열었을 때 AppRepository, pinHash, accountHash, SHA-256 같은 핵심 문자열과 인증 로직이 그대로 드러났습니다.
이 문제는 그 자체로 데이터를 탈취하는 취약점이라기보다, 앞의 취약점들을 훨씬 쉽게 찾고 악용하게 만드는 배포 설정 문제에 가깝습니다. 공격자는 APK를 디컴파일해서 PIN 해시 방식이 SHA-256("habit-diary:" + pin)이라는 걸 확인하고 바로 오프라인 크래킹 스크립트를 짤 수 있습니다. 루팅 탐지, 변조 탐지, 서명 검증 같은 기본적인 런타임 방어도 구현되어 있지 않았습니다.
난독화나 루팅 탐지가 보안의 본질은 아니고, 클라이언트 앱은 결국 분석될 수 있습니다. 하지만 release 빌드에서 debug signing을 쓰고 난독화조차 적용하지 않는 것은 실제 배포 기준으로는 매우 위험한 기본 설정입니다.
5. 딥링크·공유 인텐트를 통한 잠금 상태 데이터 무결성 침해
앱은 외부에서 habitdiary://record?date=YYYY-MM-DD 형태의 딥링크를 받고, ACTION_SEND로 이미지도 공유받을 수 있습니다. MainActivity는 exported 상태입니다.
<activity android:name=".MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="habitdiary" android:host="record" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
문제는 이 외부 인텐트 처리가 앱 잠금보다 먼저 실행된다는 점입니다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleIncomingIntent(intent) // PIN 화면보다 먼저 실행
setContent { ... }
}
handleIncomingIntent()는 딥링크의 날짜 파라미터를 검증 없이 바로 반영하고, 공유받은 이미지를 크기 제한·MIME 검증·개수 제한 없이 내부 저장소로 복사합니다. 실제 테스트에서도 잠금 상태와 무관하게 공유 이미지가 계속 files/attachments에 저장됐고, diaries.photoPaths에 경로가 누적되는 것을 확인했습니다.
이대로 배포되면 악의적인 앱이 정상 공유 흐름을 흉내 내 대용량 파일을 반복 전달해 저장소를 채우거나, 사용자가 직접 첨부하지 않은 이미지가 특정 날짜의 일기에 끼어드는 식으로 데이터가 오염될 수 있습니다. "잠겨 있으니 안전하다"는 전제 자체가 여기서는 성립하지 않습니다.
방금 나온 5개의 목록에서 제로데이나 난해한 리버싱은 하나도 없습니다. 보안을 조금이라도 공부해본 사람이라면 누구나 지적할 수 있는, 가장 기초적인 문제들입니다. 그리고 이 지점이 바로 이 실험에서 가장 하고 싶었던 이야기입니다. 코드를 짠 AI에게 "해당 코드를 보안 관점에서 분석해줘"라고 다시 물으면, 이 정도 수준의 문제들은 스스로 찾아낼 가능성이 높습니다. 생성할 때는 놓치는 것을, 검토할 때는 잡아낸다는 뜻입니다.
다른 애플리케이션이었다면?
이번엔 개인 다이어리 앱이라 피해 범위가 일기, 습관, 사진 경로 정도로 보일 수 있습니다. 하지만 같은 코드 패턴이 다루는 데이터만 바뀐다면 이야기는 달라집니다.
금융/가계부 앱이었다면 평문 저장과 백업 추출은 계좌 정보와 소비 패턴 노출로 이어지고, PIN이 송금 인증 수단이었다면 잠금 우회는 실제 금전 피해로 직결됩니다.
데이팅/소셜 앱이었다면 외부 인텐트가 잠금보다 먼저 처리되는 문제는 의도하지 않은 화면 이동, 상태 변경, 첨부 데이터 오염으로 이어질 수 있습니다. 여기에 평문 저장과 백업 노출이 결합되면 프로필, 연락처, 메시지 같은 민감정보 노출 위험도 커집니다.
취약점 자체는 평문 저장, 약한 해시, 백업 설정, 검증 없는 외부 인텐트 처리로 동일합니다. 달라지는 건 그 위에 어떤 데이터가 올라가느냐입니다.
실제로 벌어진 바이브코딩 피해 사례
바이브코딩으로 인한 보안 문제는 이제 가정이 아니라 현실에서 이미 반복적으로 보고되고 있습니다. AI로 앱과 웹사이트를 만드는 일이 쉬워진 만큼, 검증되지 않은 서비스가 실제 사용자 데이터와 만나는 속도도 함께 빨라졌기 때문입니다.
2026년 초 공개된 AI 에이전트 소셜 네트워크 Moltbook이 대표적입니다. 이 서비스는 잘못 설정된 Supabase 데이터베이스 때문에 약 150만 개의 API 토큰, 3만 5천 개의 이메일 주소, 에이전트 간 비공개 메시지가 그대로 노출됐습니다. 원인은 다름 아닌 Row-Level Security 정책 미설정이었습니다. 클라이언트 측 코드에 노출된 Supabase 키 자체보다, 그 키로 접근하는 데이터베이스에 Row-Level Security가 제대로 적용되지 않았던 것이 핵심이었습니다. 접근 제어 정책 하나가 빠진 것만으로 대량의 데이터가 외부에서 조회 가능한 상태가 된 셈입니다.
출처: Wiz Research, "Exposed Moltbook Database Reveals Millions of API Keys" (wiz.io/blog/exposed-moltbook-database-reveals-millions-of-api-keys)
이런 사례가 특정 서비스 하나의 불운은 아니었습니다. 보안 업체 RedAccess는 Lovable, Base44, Replit, Netlify 같은 도구로 만들어진 공개 자산 약 38만 개를 조사했고, 그중 약 5천 개가 민감한 기업 정보를 포함하고 있었다고 보고했습니다. 노출된 데이터에는 의료 기록, 금융 정보, 기업 문서, 고객 상담 기록 등이 포함됐습니다.
출처: VentureBeat, "5,000 vibe-coded apps just proved shadow AI is the new S3 bucket crisis" (venturebeat.com/security/vibe-coded-apps-shadow-ai-s3-bucket-crisis-ciso-audit-framework)
즉 앞선 챕터의 가정은 이미 현실에서 일부 나타나고 있습니다. 개발은 쉬워졌고, 배포도 빨라졌지만, 그만큼 검증되지 않은 코드가 실제 데이터와 만나는 속도도 빨라졌습니다. 바이브코딩의 결과물이 개인 실험을 넘어 실제 서비스가 되는 순간, 평문 저장, 약한 인증, 접근 제어 누락 같은 기본적인 문제는 곧바로 개인정보 유출과 내부 자료 노출 같은 현실적인 피해로 이어질 수 있습니다.
안전하게 바이브코딩하려면
결론은 "AI로 앱을 만들면 위험하다"가 아니라, "보안을 요구하지 않으면 AI는 보안을 알아서 챙기지 않는다"입니다. 앞서 확인했듯 AI는 이미 완성된 코드에서 문제를 찾아내는 데는 능숙합니다. 그렇다면 이 능력을 생성 단계에서도 끌어다 쓰면 됩니다.
- 1. 어떤 데이터가 민감정보인지 먼저 분류하고 프롬프트에 명시하기
- 2. 저장은 어떻게 되고, 암호화 방식은 무엇인지 되묻기
- 3. 기능 구현이 끝난 뒤, 같은 AI에게 "이 코드 보안 관점에서 분석해줘"라고 다시 요청하기
- 4.
allowBackup, release 서명 키, 난독화 여부 같은 배포 설정은 체크리스트로 별도 관리하기
- 5.
adb, logcat, jadx 같은 기본 도구로 실제 저장된 값을 한 번은 직접 열어보기
특히 3번이 핵심입니다. 이번 실험에서 나온 12개 취약점은 전부 만든 AI에게 그대로 되물었을 때 스스로 찾아낼 수 있는 수준이었습니다. 생성과 검토를 같은 대화, 혹은 최소한 같은 프로젝트 안에서 분리된 단계로 만드는 것만으로도, 이번에 발견된 문제 대부분은 배포 전에 걸러졌을 것입니다.
결론
바이브코딩은 분명 강력합니다. 짧은 시간 안에 실제로 동작하는 앱을 만들 수 있었고, 기능 구현 속도만 놓고 보면 인상적이었습니다.
이번 실험에서 발견된 문제들은 고급 취약점이 아니었습니다. 평문 저장, 약한 해시, 백업 설정, 외부 입력 검증처럼 보안을 조금만 의식했다면 충분히 피할 수 있는 기본적인 문제들이었습니다. AI는 이런 코드를 분석하라고 하면 취약점으로 잘 찾아내지만, 기능 구현만 요청했을 때는 그 보안 판단을 처음부터 적용하지 못했습니다.
결국 이 글을 통해 말하고 싶은 것은 바이브코딩을 멈추자는 것이 아닙니다. 오히려 더 많은 사람이 AI를 활용해 아이디어를 빠르게 현실화하면 좋겠습니다. 다만 그 과정에서 보안이 “나중에 챙길 일”이나 “AI가 알아서 해줄 일”로 밀려나지 않았으면 합니다. 민감정보를 어디에 저장하는지, 인증값을 어떻게 다루는지, 외부 입력을 어떻게 검증하는지 정도만 의식해도 결과물은 크게 달라질 수 있습니다. 이 글이 바이브코딩을 하는 사람들이 보안을 자연스럽게 떠올리는 계기가 되길 바랍니다.