SetLog App Static Analysis Report: A Review of the Encryption Structure and Disclosure Consistency
Author: Cyber-Lenin Date: 2026-04-25 Subject: com.newchat.setlog (New Chat Inc.) Android app Document nature: Public research. Please cite the source when quoting.
0. Summary
SetLog is a closed video-sharing social app developed and distributed by New Chat Inc. The official privacy policy states that user content such as photos, videos, and messages is end-to-end encrypted (E2EE), so the company cannot see the contents. This report statically analyzes the APK binary of the Android beta build (v1.0) distributed on Google Play to examine whether this claim is actually implemented, the permission and infrastructure model, and consistency with app store disclosures.
Key findings:
- The encryption implementation is real. The app assembles and uses the hybrid public-key encryption envelope specified by the
X25519-HKDF-SHA256+CHACHA20-POLY1305identifier directly. The master key is protected in the Android Keystore. - However, the key directory trust model is server-dependent. There is no UI, such as a safety number or QR code, that would let users verify the other party's public key. In other words, if the server delivers a forged or tampered public key, a MITM attack is theoretically possible. (See § 4-4 for details.)
- The app's control plane points to an AWS API Gateway and WebSocket in the United States, us-east-1 (Virginia). The privacy policy only states that the media S3 bucket is in Seoul, and does not disclose the region for message metadata or signaling traffic.
- The Apple App Store disclosure ("Data Not Collected") is not consistent with the privacy policy. The privacy policy states that the app collects names/usernames, IP addresses, device information, cookies, and the like. These items are not subject to E2EE, so there is no basis for excluding them from the data disclosure.
- No analytics or advertising SDKs were found in the app itself. There is no third-party data-transmission code other than Firebase Cloud Messaging.
- The permission model is conservative. Location, contacts, and external storage permissions are not declared at all.
0-1. What "MITM Risk" Means — A Plain-Language Explanation
Key finding #2 is the most important and also the hardest to understand. Let me unpack it intuitively.
Analogy: Think of the public key as a lock, and the private key as the key that opens that lock.
- A lock (public key) can be taken by anyone, and copying it is harmless. That is because merely holding the lock does not let you open a locked box.
- The key (private key) is held only by the owner and is confined to the security module in the owner's phone (Android Keystore), so it never leaves the device.
The server plays the role of a repository that gathers friends' locks. To be more precise about the actual media, it does not lock the video file with the public key directly; instead, it encrypts the video with a random content key and then sends a wrapped key, which wraps that content key with a per-recipient public key, along with it. When A wants to send a video to B:
Normal flow ✅
─────────────────────────────────────────────────────────
[A's phone] [Server = lock repository] [B's phone]
│ │ │
│ "Give me B's lock" or
│ "Give me info on the room B is in" ─▶│ │
│◀──── B's real public key/kid ─│ │
│ │ │
Video is encrypted with content key │ │
content key is wrapped as B's wrapped key │
│ │ │
│── encrypted video + B's wrapped key ─────▶│ ── relayed as-is ─▶│
│ │ unwrap wrapped key with B's private key,
│ │ watch video with content key
(server knows the public key and the ciphertext but cannot see them, lacking B's private key)
The problem is — what happens if the server lies?
MITM attack ❌
─────────────────────────────────────────────────────────
[A's phone] [Malicious server] [B's phone]
│ │ │
│ "Give me B's lock" or
│ "Give me info on the room B is in" ─▶│ │
│ │ (real B's lock kept separately) │
│◀── server's fake public key/kid ─│ │
│ ("This is B's") │ │
│ │ │
Video is encrypted with content key │ │
content key is wrapped as server's wrapped key │
│ │ │
│── encrypted video + server's wrapped key ───▶│ │
│ 🔓 server obtains content key with its own private key
│ can decrypt video with content key │
│ │ │
│ re-wraps same content key as B's wrapped key
│ │── encrypted video + B's wrapped key ─▶│
│ │ B watches video normally
👤 Both A and B think "the video went back and forth normally"
👤 No trace anywhere on either device that "the server looked in the middle"
Why it cannot be prevented: A has no way to compare whether the lock it received is the real B's or a fake sent by the server. Signal and WhatsApp show a safety number and a QR code so that friends can meet in person and compare whether the locks have the same shape. SetLog has no such comparison UI. That is:
| Threat | SetLog's Defense |
|---|---|
| An external hacker intercepts the communication | ✅ Blocked (both TLS and the E2EE envelope work) |
| The server is compromised and keys leak without the operator's knowledge | ✅ Content is safe (the private key is not on the server) |
| The operator decides to swap the locks directly | ❌ No means to prevent it |
| A law enforcement agency forces the operator to swap the locks | ❌ No means to prevent it |
→ The privacy policy statement that "the company cannot see the contents" rests on the assumption that the operator does not lie, on top of an E2EE that does work technically. The security industry calls this the absence of key transparency.
1. Method
Subject of Inspection
- 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
- Parse APK Signing Block v2 → extract signing certificate and verify with OpenSSL
- ZIP entry inventory → map DEX, native libraries, assets, META-INF
classes.dex(4.5MB) → extract R8 decompilation output (Java pseudocode) and 23,592 ASCII strings- Convert
AndroidManifest.xmlto text and audit permissions, intent filters, and exported components - For encryption code paths and network endpoints, use keyword grep + direct reading of classes
- Directly check the official privacy policy (
https://newchat.kr/privacy/) and app store disclosures (Apple App Store Korea page, Google Play Data Safety)
2. Verifying the Authenticity of the Distributed Build
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. Since the stamps of all splits match, there are no traces of tampering in any individual split either.
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 |
| Signing 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 a key held by Google Play's App Signing program. It is a normal pattern in which the developer delegates its own upload key to Google, and it is typical for the Subject/Issuer to be "Google Inc. — Android".
3. Permission Model
The 11 permissions declared by AndroidManifest.xml and an assessment:
| Permission | Risk Level | Notes |
|---|---|---|
| INTERNET / ACCESS_NETWORK_STATE / WAKE_LOCK | Obvious | network / keeping execution alive |
| POST_NOTIFICATIONS | Low | Android 13+ notifications |
| CAMERA / RECORD_AUDIO | Requires user consent | core feature (video recording) |
| USE_BIOMETRIC / USE_FINGERPRINT | Low | protect keys with biometric authentication |
c2dm.RECEIVE |
Obvious | FCM push |
com.android.vending.CHECK_LICENSE |
Obvious | Play licensing |
…DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION |
Obvious | protection of own components |
Risky permissions not declared — and therefore absolutely impossible to collect in code:
- Location:
ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION - Contacts:
READ_CONTACTS - External storage:
READ_EXTERNAL_STORAGE,READ_MEDIA_IMAGES,READ_MEDIA_VIDEO - SMS, call logs, background location, calendar, background microphone access
This means that the "approximate location information" that the privacy policy states is 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 exported components are only standard patterns such as MainActivity (LAUNCHER), Firebase system receivers, and Google Play system receivers. There is no own service exposed externally.
4. Encryption Structure
This is the most important part of this report. I examine the app's encryption structure by dividing it into (a) key management, (b) message/media envelope format, and (c) libraries used.
4-1. Key Management: Android Keystore Master Key + AES-GCM wrap
The defpackage/g8.java class is the ID key manager. Key decompiled excerpt:
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
Key key = keyStore.getKey("setlog.identity.master", null);
// 없으면 새로 생성:
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) remains in AndroidKeyStore and cannot be extracted in plaintext. Where possible, it is backed by the device’s TEE or StrongBox hardware security module (this depends on device capability).
With this master key, the user’s X25519 ID key pair is wrapped using AES-256-GCM and stored in SharedPreferences setlog.identity in the form of IV+ciphertext. The key namespaces visible in the DEX strings are:
| Namespace | Purpose | |
|---|---|---|
setlog.identity.master |
Master KEK (AndroidKeyStore) | |
setlog.identity.legacy |
Legacy ID key (for migration) | |
newchat.identity.v3.<id> |
Current ID key | |
setlog.identity.pending.<id> |
Key in transition | |
| `setlog.identity.backup.<hash>.<a\ | b>` | Wrapped key pair for backup |
setlog.key_transfer.device / …pending |
Inter-device key transfer pairing state |
The UI labels of resource (strings.xml) match 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 in which the user moves keys to a new device is implemented at the UI level. This is circumstantial evidence suggesting that keys are not stored in plaintext on the server (it is not conclusive proof — dynamic analysis is needed to determine whether a separate path exists in which the server participates in key transfer).
4-2. Message/Media Envelope Format
defpackage/iu1.java contains the envelope assembly/disassembly logic. Excerpt:
// 수신자별 wrapped-key 엔트리 생성:
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
);
In a separate code path in defpackage/uw1.java, message envelope serialization can be confirmed:
Map envelope = mapOf(
"v" -> 1,
"alg" -> "X25519-HKDF-SHA256+CHACHA20-POLY1305",
"senderEphemeralPubB64" -> ..., // 송신자 단발성 X25519 공개키
"saltB64" -> ...,
"aadB64" -> ..., // 추가 인증 데이터
"ctB64" -> ..., // ChaCha20-Poly1305 ciphertext
"kid" -> ..., // 수신자 키 ID
"publicKeyB64" -> ...
);
The read flow (iu1.java c()/d()/k()) is as follows:
- From the per-recipient wrapped-key list, find the entry matching one’s own ID.
- If none exists, throw the
"No wrapped key entry for current user"exception — this is precisely the standard E2EE pattern. - Using the matching entry’s
senderEphemeralPubB64and one’s own X25519 private key, perform ECDH → derive the KEK via HKDF-SHA256. - Unwrap the content key K with ChaCha20-Poly1305.
- Decrypt the body (ChaCha20-Poly1305) with K.
The presence of senderEphemeralPubB64 means sender-side forward secrecy. Even if the sender’s long-term private key is later exposed, the content keys of already transmitted envelopes cannot be derived.
This protocol combination is effectively the same primitive composition as the base mode of RFC 9180 (HPKE — Hybrid Public Key Encryption).
4-3. Cryptographic Libraries Used
| Library | Found | Notes |
|---|---|---|
| BouncyCastle ChaCha20-Poly1305 engine | Found (defpackage/us.java) |
AEAD core |
| Android Keystore + AES-GCM | Found (g8.java) |
Master key wrap |
| In-house X25519 ECDH handling | Found (iu1.java) |
Accompanied by the error message "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 vetted high-level libraries (libsignal, libsodium, Tink).
4-4. Key Verification — Limits of the Trust Model
For E2EE to be effective, the sender must have the recipient’s real public key. Generally, one of two models is used:
- User verification model: Signal’s safety numbers, WhatsApp’s QR codes, etc. — users compare public-key integrity out-of-band (outside the app). It is like friends meeting in person and checking, “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 the keys the server provides as-is. There is no verification procedure.
SetLog static analysis results:
- Keywords such as
safety.number,key_fingerprint,verify_identity,fingerprint.compare: 0 hits - The single "fingerprint" hit is an email-verification enum (
{ENTER_EMAIL, VERIFY_CODE, ENROLLMENT_COMPLETE}) and unrelated - No key verification/comparison UI labels in
strings.xml - The room-join path
Loi2.a0(collectionId, code)parses thecollections/{id}/joinresponse'scollectionobject. Thiscollection.participants[], viaLsr2.a(), enters theUsermodel, and it includes, as-is, thepublicKeyandkidfields provided by the server. - The media key wrapping path
Liu1.l()uses the recipientUser’suserId,publicKey, andkidto createMessageWrappedKey(uid, kid, v, alg, saltB64, wrappedB64). In other words, the source of the counterpart’s public key used by the sender is the participant/user record in the server response. - Strings such as
SERVER_KID_MISMATCH,SERVER_MISSING_PUBLIC_KEY_AND_KID, andCurrentUserKeyHealthSnapshot(...)are found. However, these appear to be consistency checks between the currently logged-in user’s own local identity key and the server account record, and are separate from defenses in which the user directly verifies the counterpart’s public key or verifies it via a public log.
→ SetLog is a server trust model. To the extent verifiable by static analysis, if the server acts maliciously or an attacker who has compromised server privileges responds by inserting a different key in place of recipient X’s public key, the client is highly likely to use it without user verification. In this case, the server/attacker can perform a MITM by unwrapping the content key with that key’s private key and then re-wrapping it with the real recipient’s key. This is similar to the trust-model limitations of iMessage.
4-4-1. How a MITM Attack Works — Step-by-Step Explanation
Premise: a public key is a lock, and a private key is that lock’s key. Duplicating a lock is harmless — opening the locked box requires the key, and the key exists only inside its owner’s phone.
The server acts as a repository holding the locks of all registered users. When A goes to get B’s lock, the outcome depends on which lock the server hands over.
Scenario 1 — Honest Server
[A's phone] [Honest Server] [B's phone]
│ │ │
① "I want to send a video to B" │ │
│ │ │
② "Give me B's lock" or
"Give me info on the room B is in" ─────────▶│ │
│ [Server's lock repository] │
│ ┌──────────────────┐ │ │
│ │ A's lock 🔒A │ │ │
│ │ B's lock 🔒B │ │ │
│ │ C's lock 🔒C │ │ │
│ └──────────────────┘ │ │
│◀──── 🔒B (real public key/kid) ─│ │
│ │ │
③ Wrap the video's content key with 🔒B
as a wrapped key for user B │ │
│ 📦🔒B (locked video) │ │
│ │ │
④ Upload locked video ──────────────▶│ ─── forward as-is ──────────▶│
│ │ ⑤ With B's key 🗝️B
│ │ open 📦🔒B and watch
│
The server knows lock 🔒B, but
it lacks key 🗝️B, so it cannot see
Scenario 2 — Lying Server (MITM)
[A's phone] [malicious server] [B's phone]
│ │ │
① "I'll send B the video" │ │
│ │ │
② "Give me B's lock" or
"Give me the room info for B" ─▶│ │
│ ┌──────────────────┐ │ │
│ │ B's lock 🔒B (real) │ ← kept hidden separately │
│ │ Server lock 🔒S │ ← the fake for A │
│ └──────────────────┘ │ │
│◀──── 🔒S / kid fabricated by the server ─│ │
│ ("This is B's") │ │
│ │ │
③ Wrap the video content key with 🔒S
as a server-side wrapped key │ │
│ 📦🔒S (encrypted video + server-side wrapped key) │ │
│ │ │
④ Upload the locked video ──────▶│ │
│ 🔓 Server uses its own key 🗝️S │
│ to obtain the content key and decrypt the video │
│ │ │
│ ⑤ The same content key is rewrapped │
│ with 🔒B (real), or the plaintext re-encrypted │
│ │─── 📦🔒B delivered ───────▶│
│ │ ⑥ With B's key 🗝️B,
│ │ normal viewing
❗ Both A and B perceive only that "the video went / arrived fine, as usual"
❗ No trace remains anywhere on the devices that the server saw it midway
❗ The server can decide to carry out this attack selectively, only against certain users
(e.g., only a specific person's videos, only a specific group chat, only specific dates)
4-4-2. Why the user cannot detect it
Standard verification means (Signal · WhatsApp model):
- Each user's screen displays the other's public key fingerprint (e.g.,
XK8M-9P2Q-ABCD) - Meet in person or compare the two people's screens via another channel → if they match, the server is honest; if they differ, tampering is detected
SetLog has no such comparison UI at all. That is:
- A has no information with which to distinguish whether the lock it received is the real B's or a fake made by the server.
- B likewise has no way to confirm whether its own lock was delivered accurately to its friends.
- Because the device's local key cache stores the key the server sent as-is, a lying key also appears as a "normal cache."
This is not a defect in the cryptographic primitives themselves. X25519, HKDF, and ChaCha20-Poly1305 all function correctly, and in a scenario where an external attacker intercepts the communication, they cannot crack the envelope. The point of failure is a defect in the operational model: the user has no means to verify whether the lock the sender received is the real one. The last square of E2EE is left empty by the absence of a user-verification UI.
4-4-3. Threat model summary
| Actor | Can access content plaintext? | Notes |
|---|---|---|
| External attacker (intercepts communication only, without server compromise) | ❌ | Blocked by the TLS + E2EE envelope |
| External attacker (server compromise, database exfiltration) | ❌ | The DB holds only ciphertext, and the private keys are inside the devices |
| External attacker (gains arbitrary code execution on the server) | ✅ | Can forge the key directory and MITM |
| New Chat Inc. operators (voluntary decision) | ✅ | The key directory is under the operators' control |
| U.S. law enforcement (subpoena · NSL) | ✅ | Can be compelled against the us-east-1 infrastructure |
| South Korean law enforcement | △ | The Seoul S3 holds only ciphertext. The key directory is in us-east-1 → U.S. cooperation required |
→ E2EE that genuinely works against external threats (hackers). A structure with virtually no means of defense against internal threats (operators, law enforcement). The privacy policy's "we cannot see the content" is true in the first sense but not in the second — the fact that users find it hard to distinguish between the two is the essential risk.
4-4-4. How other services solve it
| Service | Key verification model |
|---|---|
| Signal | Safety number — displays a 60-digit number on screen, directly comparable. Automatic notification on key change |
| QR code + 60-digit number, scannable in person. Notification on key change (optional) | |
| iMessage | No verification UI → the same weakness as SetLog. Long criticized by security researchers |
| iMessage Contact Key Verification (2024–) | An optional feature Apple added belatedly. The user must turn it on |
| WhatsApp Auditable Key Directory (2023–) | If the server lies, it is recorded in a cryptographically verifiable log, making detection possible after the fact |
| SetLog | No verification UI, no key transparency infrastructure |
Features to add if SetLog seriously strengthens security in the future:
- A "my safety number" screen showing one's own public key fingerprint
- Display of each friend's public key fingerprint + notification on change
- (Ideally) Post-hoc verification infrastructure such as an Auditable Key Directory
4-5. The unaudited risk of the self-assembled protocol
Even when standard primitives are used, subtle defects in the protocol assembly itself can exist. For example: if the AAD (Additional Authenticated Data) does not include message metadata, a reordering attack; if the identity-key context binding is missing, permanent impersonation after key compromise, and so on.
Proven implementations such as Signal Protocol, MLS, and libsignal have verified these details through academic papers and external audits. The self-assembled protocol used by SetLog has no published specification or external audit record (as of search on 2026-04-25). This is the most important unknown item in this static analysis.
5. Network endpoints and the data plane / control plane
Hardcoded endpoints identified by 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 the DEX (estimated): /upload, /messages, /message, /payload, /join, /leave, /edit, /remove, /complete. No trace of GraphQL.
Distinction between the data plane and the control plane
Section 6 of the privacy policy (overseas transfer) reads as follows:
"Storage location of name (or username): Northern Virginia, United States (us-east-1)"
"Storage location of photos and videos: Seoul, Republic of Korea"
"Other user data: stored in an end-to-end encrypted state"
Facts added by this static analysis:
- The media binaries are highly likely to be in the Seoul S3 as stated in the privacy policy (dynamically verifiable via CloudFront response headers).
- However, the control plane — authentication, key directory, message metadata, push tokens, real-time signaling — all points to us-east-1 (Virginia).
- The privacy policy states only that "names are in us-east-1," and is silent on which region processes message metadata and communication logs.
→ It is reasonable to regard metadata such as the fact that a message was sent and received, its time, user IDs, and the communication graph as being under U.S. law enforcement jurisdiction. This is an item that should be classified as a disclosure defect 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 (Sentry, Crashlytics, Mixpanel, Amplitude, PostHog, Datadog, NewRelic all not found) |
| Advertising SDK | 0 |
| Deep link SDK | 0 (Branch.io, AppsFlyer, Adjust not found) |
Section 5 of the privacy policy states, "In principle, we do not provide users' personal information to outside parties." The static analysis strongly supports this proposition at the binary level — no external data transmission code paths are found other than Firebase (Google) and AWS (the company's own infrastructure).
7. Review of consistency with disclosed materials
7-1. The company's 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 an inquiry: email, name, and other content the user voluntarily enters"
"Messages, photos, videos, and other user data may be stored in an end-to-end encrypted state in the course of providing the service, and we cannot see their contents"
"Automatically collected: access 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, and access times, and information via cookies and similar technologies"
§ 6. Overseas transfer
"The name (or username) is stored on AWS in the Northern Virginia (us-east-1) region of the United States"
"Photos and videos are stored in an end-to-end encrypted state in an AWS bucket in the Seoul region of the Republic of Korea"
§ 3. Retention period
"Log records: retained for up to 1 year for security and service improvement purposes, then destroyed"
§ 4. Provision to third parties
"In principle, we do not provide users' personal information to outside parties"
Exceptions "where required by law or where there is a request pursuant to lawful procedures by an investigative agency"
Last updated: 2026-04-25
7-2. Consistency between the static analysis and the privacy policy
| Privacy policy claim | Static analysis result | Assessment |
|---|---|---|
| "Messages, photos, and videos are stored with E2EE; we cannot see their contents" | X25519+HKDF+ChaCha20-Poly1305 envelope implementation confirmed | ✅ Consistent at the primitive/structure level. However, the absence of a key verification UI means a server-trust model. |
| "Names are stored in us-east-1" | Both API/WS are in us-east-1 (Virginia) | ✅ Consistent. However, the fact that the entire control plane is in us-east-1 is additional. |
| "Photos and videos are stored in Seoul" | The CDN is global CloudFront. The S3 region cannot be determined by static analysis. | ◔ Not statically verifiable. Dynamic analysis required. |
| "Automatic collection of location information (approximate)" | 0 location permissions → only IP-based estimation possible | ✅ Consistent (not GPS). |
| "Not provided to third parties (law enforcement exception)" | 0 analytics/ad/deep link SDKs. No external transmission other than Firebase/AWS | ✅ Consistent at the binary level. |
| "E2EE retention until the user deletes it" | Outbox/encryptedFilePath pattern, mediaCipherVersion versioning found | ✅ Consistent structure. |
| "Logs retained for up to 1 year" | Not statically verifiable — server policy | — |
7-3. Apple App Store disclosure (apps.apple.com/kr/app/setlog/id6587576438) — directly confirmed
The Apple disclosure section reads as follows:
"Privacy — The developer does not collect any data from this app"
(Directly confirmed on 2026-04-25. App version: iOS 2.1.4, 90.7MB, 12+ rating, rating 4.3/98 reviews)
This disclosure is not consistent with the company's own privacy policy. The privacy policy states that it collects the following:
- 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 outside the scope of E2EE. Apple's App Privacy disclosure guide requires that "even if data is collected, if it is not linked to the user or not used for tracking," it be disclosed under a separate category, and "no data collected" may be indicated only 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 that it stores it in an identifiable form in us-east-1.
Whether E2EE content can be excluded from disclosure is a separate issue. Apple's guidelines grant a disclosure exemption only for "data encrypted such that the developer can never decrypt it." This static analysis has confirmed that SetLog's E2EE satisfies that condition at the primitive level. Accordingly, the non-disclosure of content (messages and media) can be justified. However, non-E2EE items such as names, IP addresses, device information, and cookies still carry a disclosure obligation. Therefore, the "no data collected" label is not accurate.
This discrepancy is a matter that the operator could explain or correct, or that Apple could review. This report does not reach a legal conclusion of violation; it records a factual discrepancy between two public documents (the company's own privacy policy and its App Store disclosure).
7-4. Google Play Data Safety (play.google.com/store/apps/datasafety?id=com.newchat.setlog) — Direct Verification
| 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 |
(Verified directly on 2026-04-25)
The Google Play disclosure is closer to the privacy policy than the Apple disclosure is (it explicitly declares email as a collected item). However:
- Name/username: the privacy policy § 1 specifies collection "at account creation," but it does not appear among the Google Play disclosure items (name is usually declared separately under Personal info → Name).
- IP, device information, and cookies are likewise listed in the privacy policy as automatically collected, but this report could not directly verify whether they are disclosed under the Google Play "Device or other IDs" / "App activity" categories (the webpage response was limited to certain categories).
→ The Google Play disclosure shows a higher degree of consistency than Apple's, but the possibility of missing disclosure for the name, IP, and device information categories remains.
8. Unverified Items — Dynamic Analysis Required
Items that cannot be concluded from this static analysis and that require future dynamic traffic analysis or an official explanation from the operator:
- Whether, after a media upload, the S3 object is actually located in ap-northeast-2 (Seoul)
- Whether the push payload (FCM) contains a plaintext message preview, or conveys only envelope metadata
- Whether, when a user files a report, plaintext content is transmitted to a separate moderation endpoint (how the company's CSAM/content policy operates)
- The authentication mechanism of key directory responses — how the client accepts a server-forged public key (TOFU? certificates? change detection?)
- Whether the AAD protects the integrity of message metadata (sender/receiver IDs, timestamps)
- Whether there is a path by which the
setlog.identity.backup.*namespace is sent to cloud backup - Whether an external security audit of the self-assembled protocol exists (public audit reports and CVE search results — none as of 2026-04-25)
9. Conclusion
According to the static analysis of SetLog Android beta v1.0, the end-to-end encryption specified in the company's privacy policy exists in reality at the level of primitives and envelope structure. The combination of X25519 ECDH + HKDF-SHA256 + ChaCha20-Poly1305 AEAD, the master key protected by the Android Keystore, and the pairing flow for key transfer between devices possess the core components of the E2EE promised by the privacy policy. No extensively integrated analytics or advertising SDKs were found, and the permission model is conservative.
However, the following three items determine operational security and disclosure completeness:
- Key directory trust model: There is no UI allowing users to verify the other party's public key. Under a server trust model, the E2EE can be bypassed in the event of server compromise or malice.
- Non-disclosure of the control plane region: It is certain that message metadata and signaling go to us-east-1 (Virginia), but the privacy policy specifies only the location of names as us-east-1 and is silent on the metadata region.
- The Apple App Store "no data collected" label: Considering the non-E2EE collected items specified in the privacy policy (name, IP, device information, cookies), it is not accurate. The Google Play disclosure is partially consistent.
SetLog's encryption design is closer to a "half-finished" security model than to flawed marketing. The privacy policy's promises and the client implementation align at the core, but the user verification UI, metadata region disclosure, and app store disclosure consistency are areas the operator must further refine.
Sources
- Privacy policy original text:
https://newchat.kr/privacy/(last updated 2026-04-25, accessed directly on the day this report was written) - Apple App Store:
https://apps.apple.com/kr/app/setlog/id6587576438(accessed directly on 2026-04-25) - Google Play Data Safety:
https://play.google.com/store/apps/datasafety?id=com.newchat.setlog(accessed directly on 2026-04-25) - APK static analysis: the Google Play distribution identified by the SHA-256 in § 1 of this report
- Standards referenced: RFC 9180 (HPKE), Apple App Privacy Details Guidelines, Google Play Data Safety Policy
This report was prepared solely from static code analysis and review of public documents; no dynamic analysis, traffic capture, or external security audit of the production servers was performed. Some conclusions may be updated by future app updates, an official explanation from the operator, or a third-party security audit.