SetLog App Static Analysis Report: Review of Cryptographic Structure and Disclosure Consistency
Author: Cyber-Lenin Date: 2026-04-25 Target: com.newchat.setlog (New Chat Inc.) Android App Document Nature: Public research. Please cite source when quoting.
0. Summary
SetLog is a closed-source video-sharing social app developed and distributed by New Chat Inc. Its official privacy policy states that user content—photos, videos, messages, etc.—is end-to-end encrypted (E2EE) and that the company cannot view its contents. This report statically analyzes the APK binary of the Android beta build (v1.0) distributed via Google Play, examining the actual implementation of this claim, the permission and infrastructure model, and its consistency with app store disclosures.
Key findings:
- The encryption implementation is real. The app directly assembles and uses a hybrid public-key encryption envelope explicitly identified as
X25519-HKDF-SHA256+CHACHA20-POLY1305. The master key is protected by the Android Keystore. - However, the key directory trust model is server-dependent. There is no safety number, QR code, or similar UI that allows a user to verify the counterparty's public key. Therefore, if the server provides a forged public key, a theoretical MITM attack is possible. (See § 4-4 for detailed explanation.)
- The app's control plane points to AWS API Gateway and WebSocket in us-east-1 (Virginia). The privacy policy states only that the media S3 bucket is located in Seoul; it does not disclose the region for message metadata or signaling traffic.
- The Apple App Store disclosure ("No Data Collected") is inconsistent with the privacy policy. The privacy policy states it collects name/username, IP, device information, cookies, etc. These items are not subject to E2EE, so there is no basis to exclude them from the data disclosure.
- No analytics or advertising SDKs were found in the app itself. Aside from Firebase Cloud Messaging, there is no code transmitting data to third parties.
- The permission model is conservative. Location, contacts, and external storage permissions are not declared at all.
0-1. What "MITM Risk" Means – A Simple Explanation
Finding #2 is the most important and hardest to grasp. Here is an intuitive explanation.
Analogy: Think of a public key as a padlock and a private key as the key that opens it.
- A padlock (public key) can be taken by anyone and copied without harm—having the padlock doesn't let you open a locked box.
- The key (private key) is held only by the owner, locked inside their phone's security module (Android Keystore), and never leaves it.
The server acts as a locker that stores the padlocks of friends. More precisely, media is not directly encrypted with the public key; instead, a random content key encrypts the video, and that content key is then wrapped (encrypted) for each recipient using their public key, forming a wrapped key. When A wants to send a video to B:
Normal Flow ✅
─────────────────────────────────────────────────────────
[A's Phone] [Server = Padlock Locker] [B's Phone]
│ │ │
│ "Give me B's padlock" or
│ "Give me the room info for B" ─▶│ │
│◀──── B's real public key/kid ───│ │
│ │ │
Video encrypted with content key │ │
Content key wrapped into B's wrapped key │
│ │ │
│── Encrypted video + B's wrapped key ──▶│ ── pass through ─▶│
│ │ B's private key unwraps
│ │ wrapped key, gets content key, views video
(Server knows public key and ciphertext
but lacks B's private key, cannot view)
The problem – What if the server lies?
MITM Attack ❌
─────────────────────────────────────────────────────────
[A's Phone] [Malicious Server] [B's Phone]
│ │ │
│ "Give me B's padlock" or
│ "Give me the room info for B" ─▶│ │
│ │ (Stores B's real padlock elsewhere)│
│◀── Fake public key/kid from server ─│ │
│ ("This is B's") │ │
│ │ │
Video encrypted with content key │ │
Content key wrapped into server's wrapped key │
│ │ │
│── Encrypted video + server's wrapped key ─▶│ │
│ 🔓 Server uses its own private key to get content key
│ Can decrypt video with content key│
│ │ │
│ Same content key re-wrapped into B's wrapped key
│ │── Encrypted video + B's wrapped key ─▶│
│ │ B views video normally
👤 Both A and B think "the video went through normally"
👤 No trace left on either device that the server saw the content
Why it cannot be prevented: A has no way to compare whether the padlock it received is really B's or a fake sent by the server. Signal and WhatsApp display safety numbers and QR codes so friends can meet in person and compare the shape of their padlocks. SetLog lacks that comparison UI. That is:
| Threat | SetLog's Defense |
|---|---|
| An external hacker intercepting communications | ✅ Blocked (TLS + E2EE envelope both work) |
| Server compromised, keys leaked without operator knowledge | ✅ Content is safe (private keys not on server) |
| Operator decides to swap padlocks themselves | ❌ No means to prevent |
| Law enforcement compels operator to swap padlocks | ❌ No means to prevent |
→ The privacy policy statement "the company cannot view the contents" stands on a working E2EE foundation, plus the assumption that the operator does not lie. In the security industry, this is called lack of key transparency.
1. Methodology
Target of Analysis
- XAPK bundle (Google Play distribution)
- Package:
com.newchat.setlog - versionName
1.0, versionCode10 - minSdk 32 (Android 12L), targetSdk 36 (Android 16)
- XAPK SHA-256:
5aa92842a8b7f9e69c33d3f03e20fdff5c8e47bb31ad6e046dcff394ab0b26a4 - base APK SHA-256:
14de20b4caf796f6a75d33bef64a07c57fb215afa25535f752fb823df98f9449 - Bundled split APKs:
arm64_v8a,en,fr,mdpi
Analysis Procedure
- Parsed APK Signing Block v2 → extracted signing certificate, verified with OpenSSL
- ZIP entry inventory → mapped DEX, native libraries, assets, META-INF
classes.dex(4.5MB) → extracted R8 decompiled output (Java pseudocode) and 23,592 ASCII strings- Textified
AndroidManifest.xml→ audited permissions, intent filters, exported components - Encryption code paths and network endpoints identified via keyword grep and direct class reading
- Official privacy policy (
https://newchat.kr/privacy/) and app store disclosures (Apple App Store Korean page, Google Play Data Safety) directly consulted
2. Distribution Authenticity Verification
2-1. Distribution Source
| Evidence | Value |
|---|---|
META-INF/com.android.stamp.source metadata |
https://play.google.com/store |
| Pairip license component | com.pairip.licensecheck.LicenseActivity registered |
| Play distribution stamp cert SHA-256 | 3257d599a49d2c961a471ca9843f59d341a405884583fc087df4237b733bbd6d (identical for base and all splits) |
→ Identified as a genuine Google Play distribution. All split stamps match, indicating no tampering in individual splits.
2-2. Signer Certificate (APK Signing Scheme v2)
| Item | Value |
|---|---|
| Subject = Issuer | C=US, ST=California, L=Mountain View, O=Google Inc., OU=Android, CN=Android |
| Signature algorithm | RSA 4096-bit, SHA-256 with RSA |
| Validity period | 2026-03-31 ~ 2056-03-31 |
| Cert SHA-256 | FD:5C:74:7C:34:C9:8F:81:02:6E:4A:22:CB:9E:8B:70:E9:5D:AB:12:2E:DB:1B:9F:6C:BE:70:FA:B8:9A:F7:62 |
| Cert SHA-1 | 5E:52:53:B6:05:DE:7A:5C:9B:2B:03:A3:66:32:BA:33:16:28:8C:8A |
| Serial | A95371D3B6835B54E0B576F587CD7AF93631E584 |
This is the result of re-signing with the key held by Google Play's App Signing program. It is a normal pattern where the developer delegates its own upload key to Google; the Subject/Issuer being "Google Inc. — Android" is standard.
3. Permission Model
The 11 permissions declared in AndroidManifest.xml and their assessment:
| Permission | Risk | Note |
|---|---|---|
| INTERNET / ACCESS_NETWORK_STATE / WAKE_LOCK | Trivial | Network, keep-alive |
| POST_NOTIFICATIONS | Low | Android 13+ notifications |
| CAMERA / RECORD_AUDIO | Requires user consent | Core functionality (video recording) |
| USE_BIOMETRIC / USE_FINGERPRINT | Low | Biometric authentication to protect keys |
c2dm.RECEIVE |
Trivial | FCM push |
com.android.vending.CHECK_LICENSE |
Trivial | Play Licensing |
…DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION |
Trivial | Self-component protection |
Not declared—therefore never collectable in code—dangerous permissions:
- Location:
ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION - Contacts:
READ_CONTACTS - External storage:
READ_EXTERNAL_STORAGE,READ_MEDIA_IMAGES,READ_MEDIA_VIDEO - SMS, call log, background location, calendar, microphone background access
This means that the "approximate location information" the privacy policy lists as automatically collected is not GPS but IP-based estimation.
Intent Filters
Deep links are restricted to two Korean domain hosts:
<data android:scheme="https" android:host="setlog.kr" android:pathPrefix="/invite"/>
<data android:scheme="https" android:host="newchat.kr" android:pathPrefix="/invite"/>
The only exported components are standard patterns: MainActivity (LAUNCHER), Firebase system receivers, Google Play system receivers, etc. No custom services are exposed externally.
4. Encryption Structure
This is the most important section of the report. We examine the encryption structure in three parts: (a) key management, (b) message/media envelope format, (c) libraries used.
4-1. Key Management: Android Keystore Master Key + AES-GCM Wrap
Class defpackage/g8.java is the identity key manager. Decompiled core excerpt:
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
Key key = keyStore.getKey("setlog.identity.master", null);
// If not exists, create new:
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES", "AndroidKeyStore");
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder("setlog.identity.master",
PURPOSE_ENCRYPT | PURPOSE_DECRYPT)
.setBlockModes("GCM").setEncryptionPaddings("NoPadding")
.setRandomizedEncryptionRequired(true).setKeySize(256).build();
→ The master key (KEK) resides in AndroidKeyStore and cannot be extracted in plaintext. When available, it is backed by the device's TEE or StrongBox hardware security module (this depends on device capability).
Using this master key, the user's X25519 identity key pair is wrapped with AES-256-GCM and stored in SharedPreferences setlog.identity as IV+ciphertext. Key namespaces observed in DEX strings:
| Namespace | Purpose | |
|---|---|---|
setlog.identity.master |
Master KEK (AndroidKeyStore) | |
setlog.identity.legacy |
Old version ID key (for migration) | |
newchat.identity.v3.<id> |
Current ID key | |
setlog.identity.pending.<id> |
Key being rotated | |
| `setlog.identity.backup.<hash>.<a\ | b>` | Backup-wrapped key pair |
setlog.key_transfer.device / …pending |
Inter-device key transfer pairing state |
UI labels in resources (strings.xml) align with this flow:
"Transfer to This Phone" / "Transfer to Another Device"
"Enter the 8-digit code shown there. This securely moves the key that unlocks your encrypted videos and messages."
"On your other device, open Account and choose Transfer to Another Device."
"You'll approve the transfer on your other device before anything moves."
→ A pairing flow for moving keys to a new device is implemented at the UI level. This is circumstantial evidence that keys are not stored in plaintext on the server (but it is not definitive proof—whether the server is involved in the key transfer path requires dynamic analysis).
4-2. Message/Media Envelope Format
defpackage/iu1.java contains the envelope assembly and disassembly logic. Excerpt:
// Create per-recipient wrapped-key entry:
bw1Var = new bw1(
str3, // recipient ID
str6, // recipient public key fingerprint (Base64 SHA-256[0..16])
i2, // version
"X25519-HKDF-SHA256+CHACHA20-POLY1305", // algorithm identifier
encodeToString(bArr2), // ephemeral salt
encodeToString(b) // wrapped content key
);
A separate code path in defpackage/uw1.java confirms message envelope serialization:
Map envelope = mapOf(
"v" -> 1,
"alg" -> "X25519-HKDF-SHA256+CHACHA20-POLY1305",
"senderEphemeralPubB64" -> ..., // sender's ephemeral X25519 public key
"saltB64" -> ...,
"aadB64" -> ..., // additional authenticated data
"ctB64" -> ..., // ChaCha20-Poly1305 ciphertext
"kid" -> ..., // recipient key ID
"publicKeyB64" -> ...
);
The read flow (iu1.java methods c()/d()/k()) is as follows:
- Find the entry in the per-recipient wrapped-key list matching the current user's ID.
- If not found, throw exception
"No wrapped key entry for current user"– this is exactly the standard E2EE pattern. - Use the matching entry's
senderEphemeralPubB64and the user's own X25519 private key to perform ECDH → HKDF-SHA256 to derive the KEK. - Unwrap content key K with ChaCha20-Poly1305.
- Decrypt the payload (ChaCha20-Poly1305) with K.
The presence of senderEphemeralPubB64 implies sender forward secrecy. Even if the sender's long-term private key is later exposed, the content key of already transmitted envelopes cannot be derived.
This protocol combination is effectively identical to the base mode of RFC 9180 (HPKE – Hybrid Public Key Encryption) in terms of primitive composition.
4-3. Cryptographic Libraries Used
| Library | Found? | Note |
|---|---|---|
| BouncyCastle ChaCha20-Poly1305 engine | Found (defpackage/us.java) |
AEAD core |
| Android Keystore + AES-GCM | Found (g8.java) |
Master key wrap |
| Custom X25519 ECDH handling | Found (iu1.java) |
Accompanied by error messages like "Invalid X25519 private/public key length" |
| Conscrypt | Found | TLS provider (HTTPS channel) |
| libsodium / NaCl | Not found | |
| libsignal (Signal Protocol) | Not found | |
| Google Tink | Not found | |
| OpenPGP | Not found | |
| MLS, Olm/Megolm | Not found |
→ The app uses standard primitives (X25519, HKDF-SHA256, ChaCha20-Poly1305, AES-GCM) in a self-assembled protocol. It does not use widely audited high-level libraries (libsignal, libsodium, Tink).
4-4. Key Verification – Trust Model Limitations
For E2EE to be effective, the sender must have the true public key of the recipient. Typically, one of two models is used:
- User verification model: Signal's safety numbers, WhatsApp's QR code, etc.—users compare public key integrity out-of-band (meeting in person to check "My code is ABC123; is the code you see for me also ABC123?").
- Server trust model: The server manages the public key directory, and users accept whatever key the server provides. No verification procedure.
Static analysis of SetLog:
- Zero instances of keywords such as
safety.number,key_fingerprint,verify_identity,fingerprint.compare - The only "fingerprint" hit is in an email authentication enum (
{ENTER_EMAIL, VERIFY_CODE, ENROLLMENT_COMPLETE}), unrelated - No UI labels in
strings.xmlfor key verification/comparison - The room join path
Loi2.a0(collectionId, code)parses thecollectionobject from thecollections/{id}/joinresponse. Thecollection.participants[]enters theUsermodel viaLsr2.a(), which directly includespublicKeyandkidfields provided by the server. - The media key wrapping path
Liu1.l()uses the recipientUser'suserId,publicKey, andkidto createMessageWrappedKey(uid, kid, v, alg, saltB64, wrappedB64). Therefore, the source of the counterparty's public key used by the sender is the participant/user record from the server response. - Strings such as
SERVER_KID_MISMATCH,SERVER_MISSING_PUBLIC_KEY_AND_KID, andCurrentUserKeyHealthSnapshot(...)are found. However, these appear to check the currently logged-in user's own local identity key against the server's account record, which is separate from a defense where users directly verify counterparty public keys or verify via a public log.
→ SetLog uses the server trust model. Within the scope of static analysis, if the server behaves maliciously or an attacker who has compromised the server responds with a different key in place of recipient X's public key, the client will likely use it without user verification. In that case, the server/attacker can unwrap the content key using the private key corresponding to that fake key, then re-wrap it with the real recipient's key—a MITM attack similar to the trust model limitation of iMessage.
4-4-1. How the MITM Attack Works – Step-by-Step Explanation
Premise: Public key = padlock, private key = key for that padlock. Anyone can copy a padlock without harm—to open a locked box you need the key, which stays inside the user's phone only.
The server acts as a locker that stores the padlocks of all registered users. The outcome depends on which padlock the server hands out when A goes to get B's padlock.
Scenario 1 – Honest Server
[A's Phone] [Honest Server] [B's Phone]
│ │ │
① "I want to send a video to B" │ │
│ │ │
② "Give me B's padlock" or
"Give me the room info for B" ─────────▶│ │
│ [Server's padlock locker] │
│ ┌──────────────────┐ │ │
│ │ A padlock 🔒A │ │ │
│ │ B padlock 🔒B │ │ │
│ │ C padlock 🔒C │ │ │
│ └──────────────────┘ │ │
│◀──── 🔒B (real public key/kid) ─│ │
│ │ │
③ Video content key wrapped
with 🔒B into B's wrapped key │ │
│ 📦🔒B (locked video) │ │
│ │ │
④ Upload locked video ──────────▶│ ─── pass through ──────────▶│
│ │ ⑤ B's key 🗝️B unlocks
│ │ 📦🔒B and watches
│
Server knows padlock 🔒B but
lacks key 🗝️B, cannot see
Scenario 2 – Lying Server (MITM)
[A's Phone] [Malicious Server] [B's Phone]
│ │ │
① "I want to send a video to B" │ │
│ │ │
② "Give me B's padlock" or
"Give me the room info for B" ─────────▶│ │
│ ┌──────────────────┐ │ │
│ │ B padlock 🔒B (real)│ ← hidden │
│ │ Server padlock 🔒S │ ← fake to give A │
│ └──────────────────┘ │ │
│◀──── 🔒S / server-crafted kid ─│ │
│ ("This is B's") │ │
│ │ │
③ Video content key wrapped
with 🔒S into server's wrapped key │ │
│ 📦🔒S (encrypted video + server's wrapped key)│ │
│ │ │
④ Upload locked video ──────────▶│ │
│ 🔓 Server uses its own key 🗝️S to│
│ get content key, decrypts video│
│ │ │
│ ⑤ Re-wraps same content key with│
│ 🔒B (real) or re-encrypts plaintext│
│ │─── 📦🔒B forward ─────────▶│
│ │ ⑥ B's key 🗝️B unlocks,
│ │ watches normally
❗ Both A and B perceive "the video went through / was received normally"
❗ No trace left on either device that the server saw it
❗ Server can decide to selectively attack only certain users
(e.g., only specific person's videos, only certain group chats, only certain dates)
4-4-2. Why the User Cannot Detect It
Standard verification methods (Signal / WhatsApp model):
- Both users' screens display each other's public key fingerprint (e.g.,
XK8M-9P2Q-ABCD) - Meet in person or use another channel to compare the two screens → identical means the server is honest; different means tampering is detected
SetLog lacks this comparison UI entirely. Hence:
- A has no information to distinguish whether the padlock it received is really B's or a fake made by the server.
- B has no way to check whether their padlock has been correctly delivered to friends.
- The local key cache on the device stores the key from the server as-is, so even a fake key appears as a "normal cache."
This is not a flaw in the cryptographic primitives themselves. X25519, HKDF, and ChaCha20-Poly1305 all function correctly; an external attacker intercepting communications cannot break the envelope. The weak point is an operational model flaw: the user has no means to verify whether the padlock they received is genuine. E2EE's final segment is missing due to the absence of user verification UI.
4-4-3. Threat Model Summary
| Actor | Can access plaintext content? | Note |
|---|---|---|
| External attacker (intercepts communication only, no server breach) | ❌ | Blocked by TLS + E2EE envelope |
| External attacker (breaches server, steals database) | ❌ | DB only contains ciphertext; private keys are on devices |
| External attacker (gains arbitrary code execution on server) | ✅ | Can forge key directory for MITM |
| New Chat Inc. operations team (voluntary decision) | ✅ | Key directory is under their control |
| US law enforcement (subpoena / NSL) | ✅ | Can compel against us-east-1 infrastructure |
| South Korean law enforcement | △ | Seoul S3 only contains ciphertext; key directory in us-east-1 → requires US cooperation |
→ Against external threats (hackers), it is genuinely working E2EE. Against internal threats (operator, law enforcement), there is effectively no defense mechanism. The privacy policy statement "we cannot view the contents" is true in the first sense but not in the second—the fact that users cannot distinguish this difference is the essential risk.
4-4-4. How Other Services Address This
| Service | Key Verification Model |
|---|---|
| Signal | Safety number – displays 60-digit number on screen, allows direct comparison. Automatic notification on key change. |
| QR code + 60-digit number, can scan in person. Notification on key change (optional). | |
| iMessage | No verification UI → same weakness as SetLog. Long criticized by security researchers. |
| iMessage Contact Key Verification (2024-) | Feature added belatedly by Apple, optional. User must enable. |
| WhatsApp Auditable Key Directory (2023-) | If server lies, it is recorded in a cryptographically verifiable log detectable after the fact. |
| SetLog | No verification UI, no key transparency infrastructure. |
If SetLog seriously strengthens security in the future, features to add:
- A "My Safety Number" screen showing own public key fingerprint.
- Display per-contact public key fingerprint + notifications on change.
- (Ideal) Post-hoc verification infrastructure like Auditable Key Directory.
4-5. Risks of Una
udited Self-Assembled Protocol
Even using standard primitives, the protocol assembly itself may have subtle flaws. For example: if AAD (additional authenticated data) does not include message metadata, replay/reordering attacks are possible; if identity key context binding is omitted, key compromise can lead to permanent impersonation.
Vetted implementations like Signal Protocol, MLS, and libsignal have validated such details through academic papers and external audits. The self-assembled protocol used by SetLog has no public specification or external audit record (as of 2026-04-25 search). This is the most important unknown item in this static analysis.
5. Network Endpoints and Data Plane / Control Plane
Hardcoded endpoints identified through DEX string extraction:
| Type | URL | Location |
|---|---|---|
| REST API | https://j6x2txqgbb.execute-api.us-east-1.amazonaws.com/prod/ |
AWS API Gateway, us-east-1 (Virginia) |
| WebSocket | wss://xxjbti8645.execute-api.us-east-1.amazonaws.com/production/ |
AWS API Gateway, us-east-1 (Virginia) |
| Media CDN | https://dsly7y76dyfdl.cloudfront.net/ |
CloudFront (global PoP) |
| Invite deep link | https://setlog.kr/invite/ |
External ingress |
REST action paths extractable from DEX (inferred): /upload, /messages, /message, /payload, /join, /leave, /edit, /remove, /complete. No traces of GraphQL.
Distinction Between Data Plane and Control Plane
Privacy policy § 6 (International Transfer) states:
"Storage location of name (or username): US Virginia North (us-east-1)"
"Storage location of photos and videos: Seoul, South Korea"
"Other user data: stored in end-to-end encrypted state"
What this static analysis adds:
- Media binaries are likely in Seoul S3 as per the policy (dynamically verifiable via CloudFront response headers).
- However, the control plane—authentication, key directory, message metadata, push tokens, real-time signaling—all goes to us-east-1 (Virginia).
- The privacy policy only specifies that "name is in us-east-1" and is silent about which region processes message metadata and communication logs.
→ It is reasonable to consider that metadata such as message send/receive fact, timestamp, user ID, and communication graph falls under US law enforcement jurisdiction. This should be classified as a disclosure gap in the privacy policy.
6. Third-Party SDK Inventory
| Category | SDKs Found |
|---|---|
| Push / Notifications | Firebase Cloud Messaging |
| Authentication | Google Play Services Auth, Credentials API (passkey support) |
| Camera / Media | androidx.camera, androidx.media3 |
| TLS Provider | Conscrypt |
| Data Storage | androidx.datastore, traces of MMKV (sqlite) |
| Licensing | com.pairip.licensecheck (Google Play anti-piracy) |
| Analytics SDK | 0 found (Sentry, Crashlytics, Mixpanel, Amplitude, PostHog, Datadog, NewRelic all absent) |
| Advertising SDK | 0 found |
| Deep link SDK | 0 found (Branch.io, AppsFlyer, Adjust absent) |
Privacy policy § 5 states: "We do not, in principle, provide users' personal information to third parties." Static analysis strongly supports this claim at the binary level—no external data transmission code paths were found beyond Firebase (Google) and AWS (their own infrastructure).
7. Consistency Review with Public Disclosures
7-1. Self-Published Privacy Policy (https://newchat.kr/privacy/) – Key Quotations
§ 1. Categories of Personal Information Collected
"When creating an account and using the service: name (or username)"
"When making inquiries: email, name, other content voluntarily entered by the user"
"Messages, photos, videos, and other user data may be stored in an end-to-end encrypted state during service provision, and we cannot view the contents."
"Automatically collected: connection IP address and approximate location information, browser type, settings and language, device information (model, OS version, etc.), website usage records such as pages visited, clicks, connection times, and information via cookies and similar technologies."
§ 6. International Transfer
"Name (or username) is stored on AWS in the US Virginia North (us-east-1) region"
"Photos and videos are stored in an end-to-end encrypted state on AWS bucket in the Seoul, South Korea region"
§ 3. Retention Period
"Log records: retained for up to 1 year for security and service improvement purposes, then destroyed."
§ 4. Provision to Third Parties
"We do not, in principle, provide users' personal information to third parties"
Exception when "required by law or requested by investigative authorities through due process"
Last updated: 2026-04-25
7-2. Consistency Between Static Analysis and Privacy Policy
| Privacy policy claim | Static analysis result | Assessment |
|---|---|---|
| "Messages, photos, videos are stored E2EE; we cannot view contents" | X25519+HKDF+ChaCha20-Poly1305 envelope implementation confirmed | ✅ Consistent at primitive and structural level. However, server trust model due to lack of key verification UI. |
| "Name stored in us-east-1" | API/WS both us-east-1 (Virginia) | ✅ Consistent. But note that entire control plane is in us-east-1. |
| "Photos, videos stored in Seoul" | CDN is CloudFront global. S3 region not verifiable statically. | ◔ Cannot verify statically. Dynamic analysis needed. |
| "Location information automatically collected (approximate)" | Zero location permissions → only IP-based estimation possible | ✅ Consistent (not GPS). |
| "Not provided to third parties (law enforcement exception)" | 0 analytics/advertising/deep link SDKs. No external transmission beyond Firebase/AWS | ✅ Consistent at binary level. |
| "Stored E2EE until user deletes" | Outbox/encryptedFilePath pattern, mediaCipherVersion management found | ✅ Consistent structure. |
| "Logs retained up to 1 year" | Not statically verifiable – server policy | — |
7-3. Apple App Store Disclosure (apps.apple.com/kr/app/setlog/id6587576438) – Direct Observation
The Apple disclosure section states:
"Privacy – Developer does not collect data from this app."
(Observed directly on 2026-04-25. App version: iOS 2.1.4, 90.7MB, rated 12+, rating 4.3/98 reviews)
This disclosure is inconsistent with its own privacy policy. The privacy policy states it collects:
- Name or username (stored in plaintext in us-east-1)
- IP address and approximate location
- Device information, OS version
- Browser/usage records, cookies
These items are all not subject to E2EE. Apple's App Privacy Disclosure guidelines require separate categorization when "data is collected but not linked to the user or not used for tracking"; the label "No Data Collected" can only be displayed when no data is linked to the user (Apple App Privacy Details guidelines – 2025 revision). A username is by definition linked to the user, and the privacy policy itself states it is stored in identifiable form in us-east-1.
Whether E2EE content can be excluded from disclosure is a separate issue. Apple's guidelines permit exemption for "data that is encrypted in such a way that the developer can never decrypt it." This static analysis confirms that SetLog's E2EE meets that criterion at the primitive level. Therefore, non-disclosure of content (messages, media) may be justifiable. However, non-E2EE items such as name, IP, device information, and cookies still carry disclosure obligations. Hence, the "No Data Collected" label is not accurate.
This discrepancy is something the operating company may explain/correct or Apple may review. This report does not reach a legal conclusion of violation; it records the factual inconsistency between two publicly available documents (its own privacy policy and the App Store disclosure).
7-4. Google Play Data Safety (play.google.com/store/apps/datasafety?id=com.newchat.setlog) – Direct Observation
| Item | Google Play Disclosure |
|---|---|
| Data collected | "Email address" (Personal info, optional, for account management purposes) |
| Third-party sharing | "No data shared with third parties" |
| Encryption in transit | Yes |
| User data deletion request | Yes |
(Observed directly on 2026-04-25)
The Google Play disclosure is closer to the privacy policy than the Apple disclosure (explicitly declaring email as a collected item). However:
- Name/username is stated in privacy policy § 1 as "collected when creating an account," but the Google Play disclosure items do not include it (name is typically a separate declaration under Personal info → Name).
- IP, device information, cookies are also listed as automatically collected in the privacy policy, but whether they are disclosed under Google Play's "Device or other IDs" / "App activity" categories was not directly verified by this report (the webpage response was limited to certain categories).
→ The Google Play disclosure is more consistent than Apple's, but potential omissions for name, IP, and device information categories remain.
8. Unverified Items – Dynamic Analysis Needed
Items that cannot be concluded from this static analysis and require future dynamic traffic analysis or official explanation from the operating company:
- Whether S3 objects are actually located in ap-northeast-2 (Seoul) after media upload
- Whether push payloads (FCM) contain plaintext message previews or only envelope metadata
- Whether user reports transmit plaintext content to a separate moderation endpoint (how their CSAM/content policy operates in practice)
- Authentication mechanism of key directory responses—how the client accepts a server-forged public key (TOFU? certificates? change detection?)
- Whether AAD protects integrity of message metadata (sender/receiver ID, timestamp)
- Whether the
setlog.identity.backup.*namespace is transmitted to cloud backup - Existence of an external security audit of the self-assembled protocol (public audit reports / CVE search results – none as of 2026-04-25)
9. Conclusion
Static analysis of the SetLog Android beta v1.0 shows that the end-to-end encryption stated in its own privacy policy does exist at the primitive and envelope structure level. The combination of X25519 ECDH + HKDF-SHA256 + ChaCha20-Poly1305 AEAD, along with a master key protected by Android Keystore and a device-to-device key transfer pairing flow, implements the core components of the E2EE promised by the policy. No widely integrated analytics or advertising SDKs were found, and the permission model is conservative.
However, three items separate the operational security and disclosure completeness:
- Key Directory Trust Model: There is no UI for users to verify counterparty public keys. The server trust model allows E2EE bypass if the server is compromised or malicious.
- Non-disclosure of Control Plane Region: It is certain that message metadata and signaling go to us-east-1 (Virginia), but the privacy policy only identifies name location as us-east-1 and remains silent on metadata region.
- Apple App Store "No Data Collected" Label: This is inaccurate given the non-E2EE collected items explicitly stated in the privacy policy (name, IP, device information, cookies). The Google Play disclosure is partially consistent.
SetLog's encryption design is closer to a "half-finished" security model than a flawed marketing claim. The privacy policy's promises and the client implementation align in the core, but user verification UI, metadata region disclosure, and app store disclosure consistency are areas the operating company needs to refine further.
Sources
- Privacy policy text:
https://newchat.kr/privacy/(last updated 2026-04-25, directly observed on the day of this report's preparation) - Apple App Store:
https://apps.apple.com/kr/app/setlog/id6587576438(directly observed on 2026-04-25) - Google Play Data Safety:
https://play.google.com/store/apps/datasafety?id=com.newchat.setlog(directly observed on 2026-04-25) - APK static analysis: Google Play distribution identified by SHA-256 in § 1 of this report
- Standard references: RFC 9180 (HPKE), Apple App Privacy Details Guidelines, Google Play Data Safety Policy
This report is based solely on static code analysis and review of publicly available documents; no dynamic analysis, traffic capture, or external security audit of the operational server has been performed. Some conclusions may be updated by future app updates, official explanations from the operating company, or third-party security audits.