모바일 지갑의 프라이버시: 안드로이드 지갑 3종 APK 실측
안드로이드 지갑 세 개를 풀어 매니페스트와 코드를 읽었습니다. 푸시 SDK 없음, 크래시 리포터 없음, 백업은 클라우드로 넘기지 않음. 다만 기본 노드와 권한은 크게 다릅니다.
휴대폰에서 주소와 잔액과 IP를 동시에 아는 소프트웨어는 하나뿐입니다. 지갑입니다. 교환 사이트도, 탐색기도 아닙니다. 키를 들고 있으면서 동시에 네트워크 요청을 보내는 것이 지갑이기 때문입니다. 그래서 세 개를 열었습니다. 2026년 10월 28일 각 프로젝트의 GitHub 릴리스에서 arm64 안드로이드 빌드를 받아, 패키지 안의 바이너리 AndroidManifest.xml을 파싱하고, 컴파일된 Dart와 Java 코드에서 '말하는 부품'을 찾았습니다. 푸시, 크래시 리포트, 분석, 백업, 그리고 새로 설치했을 때 기본으로 접속하는 노드입니다.
무엇을 열었고, 정적 분석으로는 무엇을 알 수 없는지.
세 개의 패키지입니다. Cake Wallet 6.5.0(com.cakewallet.cake_wallet, versionCode 6428)은 130,627,556바이트, 2,525개 항목, 압축 해제 시 605,160,712바이트. Monero.com 6.5.0(com.monero.app, 6171)은 75,292,742바이트로 같은 코드베이스에서 코인 목록을 줄인 빌드. Stack Wallet 2.7.1(com.cypherstack.stackwallet, 2316)은 211,733,750바이트, 639개 항목, 압축 해제 시 433,735,450바이트. 방법에는 분명한 한계가 있어 한 번만 밝힙니다. 이것은 출시된 빌드의 정적 분석이며 실행 중 통신 캡처가 아닙니다. 라이브러리가 패키지 안에 있다는 것은 증명할 수 있지만, 보지 않은 곳으로 한 번도 접속하지 않았다는 것은 증명할 수 없습니다. 노드 운영자나 유동성 공급자가 반대편에서 무엇을 보관하는지도 볼 수 없습니다. 아래 내용은 모두 바이트 수, 매니페스트 속성, 바이너리에 실제로 존재하는 문자열이며 개인정보 처리방침에서 추론한 것은 없습니다. (모네로 지갑 가이드)
누출면 1: 푸시 알림.
세 패키지 모두 firebase/messaging, FirebaseMessagingService, gcm_defaultSenderId, OneSignal, UnifiedPush, ntfy에서 0건이었습니다. 존재하는 알림 장치는 flutter_local_notifications뿐이며 기기에서 직접 예약합니다. 이게 중요한 이유는 푸시 토큰이 Google/Apple 계정에 묶인 설치 단위의 안정적 식별자이고, 메시지 메타데이터만으로도 보낸 쪽이 당신이 언제 깨어 있고 언제 접속 중인지 알 수 있기 때문입니다. 푸시 SDK가 없으면 새어 나갈 토큰도 없지만, 네트워크가 깨워 줄 방법도 없어 앱이 스스로 확인해야 합니다. 차이는 여기서 갈립니다. Stack Wallet은 권한 10개, 서비스 0개, 리시버 2개. Cake Wallet은 권한 21개, 서비스 8개, 리시버 11개이며 RECEIVE_BOOT_COMPLETED, WAKE_LOCK, FOREGROUND_SERVICE_DATA_SYNC를 포함합니다. Cake는 재부팅 후에도 동기화를 계속하고 Stack은 하지 않습니다. (모네로 지갑 가이드)
누출면 2: 크래시 리포트와 서드파티 SDK.
세 패키지 모두 Crashlytics, io/sentry, AppsFlyer, Adjust, Amplitude, Mixpanel이 없습니다. Firebase는 예외 클래스 이름 세 개(FirebaseException, FirebaseExceptionMapper, FirebaseApiNotAvailableException)로만 남아 있으며 의존성 잔재이고 메시징이나 분석 서비스가 아닙니다. 차이는 다른 곳에 있습니다. Stack Wallet은 com/google/android/gms 문자열 0건, WalletConnect 0건. Cake Wallet은 Google Play services 인증·자격 증명 클래스(play/core 아래 70개 문자열)와 WalletConnect 문자열 88건을 갖고 pulse.walletconnect.org, verify.walletconnect.org, rpc.walletconnect.org를 가리킵니다. WalletConnect는 dApp 브라우저를 열 때만 동작하지만, 동작하는 순간 IP가 당신이 고르지 않은 릴레이에 도달합니다. 크래시 리포터는 기기 모델, OS 빌드, 스택 트레이스를 보내지만 이 세 빌드에는 없습니다. (모네로 지갑 가이드)
누출면 3: 백업.
세 패키지 모두 android:allowBackup="false"와 android:fullBackupContent="false"를 설정했습니다. 이 속성 하나가 시드 문구가 Google Drive 백업에 딸려 갈 수 있는지 여부를 가릅니다. 자동 백업을 끄면 안드로이드 클라우드 백업은 앱 데이터에 손댈 수 없습니다. 대신 쓰는 것은 직접 내보내는 암호 보호 파일이고 문자열도 분명합니다(backup_service.dart, 'Backup password', 'Enter backup password here', 'Incorrect backup password'). 대가도 솔직히 적습니다. 키를 Google 저장소에서 떼어내는 이 플래그는, 내보내지 않은 채 기기가 죽으면 지갑도 함께 사라진다는 뜻입니다. 내보낸 파일을 클라우드에 올리면 개발자가 걷어낸 위험을 스스로 되돌려 놓는 셈입니다. 오프라인 매체로 내보내고 암호는 파일과 분리해 보관하십시오.
누출면 4: 접속하는 노드.
새로 설치하면 기본 호스트를 조회하고, 그 호스트는 지갑 조회 때마다 IP를 봅니다. Cake Wallet은 node.cakewallet.com, mempool.cakewallet.com, ohttp.cakewallet.com을 향하고 DNS는 cloudflare-dns.com/dns-query와 dns.google.com/resolve로 DoH를 씁니다. Stack Wallet은 nodes.nanswap.com, chain.so, chainz.cryptoid.info, mempool.space, api.coingecko.com을 향합니다. 둘 다 Tor를 넣었습니다. Stack은 libtor_ffi_plugin.so(16,610,776바이트)와 socks5_proxy를 동봉하고, Cake는 torch_dart 바인딩과 socks5_proxy를 갖지만 이 APK 안에 tor 바이너리는 없으므로 파일 목록이 아니라 앱 안의 Tor 스위치로 판단해야 합니다. Tor는 '누가 IP를 보는가'를 노드 운영자에서 출구 노드로 옮기고, DoH는 '누가 DNS 질의를 보는가'를 ISP에서 Cloudflare나 Google로 옮깁니다. 둘 다 개선이지 익명화가 아닙니다. Cake는 교환 업체도 같은 바이너리에 넣었고(sideShift, StealthEX, SimpleSwap, Trocador, SwapTrade, Exolix, ChangeNOW, LetsExchange), Stack은 Exolix, Trocador, ShopInBit, WizardSwap, Nanswap을 넣었습니다. 교환 버튼을 누를 때 목적지 주소와 수량을 보는 쪽이 이들입니다. (모네로 지갑 가이드)
누출면 5: 권한 목록.
Cake Wallet은 권한 21개, Stack Wallet은 10개입니다. 흥미로운 것은 오래된 권한을 어떻게 제한했는가입니다. ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, BLUETOOTH, BLUETOOTH_ADMIN 모두 maxSdkVersion="30"이 붙어 Android 11 이하에서만 존재했고, WRITE_EXTERNAL_STORAGE는 29가 상한입니다. Android 12 이상에서 BLUETOOTH_SCAN에는 usesPermissionFlags=0x10000(neverForLocation)이 붙어 스캔을 위치 추정에 쓰지 않는다고 선언합니다. 현대 기기에서 실제로 살아 있는 것은 카메라, 알림, 생체 인증, 네트워크 상태, 그리고 Cake의 백그라운드 세트 RECEIVE_BOOT_COMPLETED, WAKE_LOCK, 명시적 REQUEST_IGNORE_BATTERY_OPTIMIZATIONS입니다. 이는 스캔들이 아니라 설계 선택으로 읽어야 합니다. 백그라운드에서 동기화하는 지갑은 노드와 더 자주 접촉하고, 노드가 보는 것은 한 번의 조회가 아니라 시간이 찍힌 패턴입니다. (모네로 지갑 가이드)
이것이 교환에서 무엇을 바꾸는가.
주문서에는 거의 영향이 없고 그 주변에는 큽니다. 주문에 필요한 것은 다섯 필드(보내는 자산, 받는 자산, 수량, 수취 주소, 환불 주소)이고 서명은 없습니다. 교환에서 지갑은 아무것도 서명하지 않으므로 교환 사이트의 로그 정책은 그림의 절반입니다(나머지 절반은 따로 썼습니다). 지갑이 쥔 절반은 어떤 IP가 수취 체인의 그 주소들과 함께 나타나는지, 그리고 기본 노드가 09:00에 전액 잔고를, 09:05에 거래소 입금 주소를 볼 수 있는지입니다. 규모를 보면 2026년 10월 28일 14:12 UTC 기준 이 사이트의 견적은 100 USDT-TRC20이 0.14643508 XMR, 1,000이 1.62493375 XMR, 1 XMR이 581.25007 USDT, 0.05 BTC가 6.64115532 XMR(1 BTC = 132.82311 XMR)이었고 카탈로그는 519개 자산, 73개 네트워크입니다. 견적은 움직입니다. 이는 스냅숏이지 약속이 아닙니다. (XMR→USDT 출구 루트)
자기 폰에서 5분 점검.
저희 스크립트 없이도 같은 확인이 가능합니다. 설정 → 앱 → 지갑 → 권한을 열고 카메라, 알림, 네트워크가 아닌 요청에는 이유를 물으십시오. 다음으로 설정 → 시스템 → 백업에서 그 지갑이 자동 백업 목록에 뜨는지 보십시오. 뜨는데 원치 않으면 앱 백업을 끄고 직접 파일을 내보내면 됩니다. adb가 있는 PC에서는 adb shell dumpsys package com.cakewallet.cake_wallet을 실행해 granted로 걸러 실제 허가 상태를 확인하십시오. 매니페스트의 소망 목록이 아니라 실체가 보이고, 포그라운드 서비스가 도는지도 드러납니다. 두 번째 의견이 필요하면 Exodus Privacy의 같은 버전 보고서가 내장 라이브러리를 독립적으로 나열합니다. 어느 것도 서버 쪽 행동을 증명하지는 못하며, 패키지 안의 내용만 보여 줍니다. (모네로 확인 대기)
짧게 정리하면.
이 세 빌드에서 지갑은 새는 쪽이 아닙니다. 푸시 토큰도, 크래시 리포터도, 클라우드 백업 플래그도 없습니다. 남은 것은 지루하지만 결정적인 부분입니다. IP를 보는 기본 노드, 그리고 백그라운드 동기화 앱이 단발 조회가 아니라 패턴을 만든다는 사실입니다. 그 계층을 먼저 고치십시오. 앱 안의 Tor 스위치를 켜거나 직접 운영하는 노드를 향하게 하고, 자동 백업은 끈 채 직접 암호화 파일을 내보내고, 주문마다 주소를 달리하고, 거래소 입금 주소를 환불 주소로 쓰지 마십시오. 위 내용은 모두 2026년 10월 28일 세 APK의 정적 분석입니다. 버전은 바뀌므로 실제 설치한 빌드에서 다시 확인하십시오. (Tor 스왑은 안전한가?)