Surveillance Findings: Age Verification as Mass Surveillance Infrastructure

🔥 Discover this trending post from Hacker News 📖

📂 **Category**:

📌 **What You’ll Learn**:

Independent decompilation of the Persona Wallet APK v1.14.0 (SDK v2.32.3, built March 11, 2026) and analysis of the web inquiry bundle from cdn.withpersona.com (inquiry-main.js, 1.8MB) reveals the full scope of Persona’s surveillance capabilities. The APK was obtained from APKPure and decompiled with jadx 1.5.5. The Roblox APK v2.714.1091 was decompiled separately to confirm the SDK integration. All findings are from publicly available APKs and client-side JavaScript served to every user. New

SDKHardcoded AES-256-GCM Telemetry Encryption Key

Every copy of the Persona SDK contains a hardcoded AES-256-GCM encryption key in TrackingEventUtilsKt.java line 22:

4ERbfREmnh82jvK5QaXOv8jZ3OQq9hKg5o/Hbb3l9bk=

All telemetry events are “encrypted” with this key before transmission to POST https://tg.withpersona.com/t. Since the key is embedded in every publicly downloadable APK, anyone can decrypt the payloads. The encryption pipeline serializes events to JSON, wraps them as , encrypts with AES-256-GCM using a 12-byte random IV, then Base64-encodes the ciphertext and sends it as 🔥. This is obfuscation, not security. A standalone Python decryptor was built and verified in round-trip testing.

Primary source Decompiled from Persona Wallet APK v1.14.0 | jadx 1.5.5 | 2026-03-31
File tracking-events-2.35.2.aar → TrackingEventUtilsKt.java, line 22
SHA-256 048e9971ef932d8dac568b5d5b271e4cacaa443f32049a8dff519bd2dc1154d6
APK package com.withpersona.app.reusablepersonas v1.14.0 (version code 1001380, target SDK 35)
APK manifest SHA-256 0daf3d5292e143d4a636e8575810849128e77f491d814d5e058ce68947d16fc1
Reproduce jadx -d out persona-wallet.apk && grep -n "4ERbfREmnh82jvK5" out/**/TrackingEventUtilsKt.java

Decompiled source (lines 18–22):

public final class TrackingEventUtilsKt {
    private static final int GCM_TAG_LENGTH_BITS = 128;
    private static final int GCM_IV_LENGTH_BYTES = 12;
    private static final int AES_KEY_LENGTH_BYTES = 32;
    private static final String TEST_OBFUSCATION_KEY = "4ERbfREmnh82jvK5QaXOv8jZ3OQq9hKg5o/Hbb3l9bk=";

SDKZero Certificate Pinning

The SDK does not implement certificate pinning. The OkHttpClient builder creates a standard client without certificatePinner(). Combined with the hardcoded AES key, a standard MITM proxy with a user-installed CA certificate can capture and decrypt all Persona telemetry from any app that embeds the SDK.

Primary source Decompiled from Persona SDK network-core-2.35.2.aar | jadx 1.5.5 | 2026-03-31
File network-core-2.35.2.aar → NetworkCoreModule.java, lines 185–227
SHA-256 df16712972d5d19d6a71da68aa9fa912257b98c0dbac6c03698fca489b729126
What to look for The okhttpClient() method builds an OkHttpClient without calling certificatePinner(). The builder chain is: addNetworkInterceptor → readTimeout → writeTimeout → connectTimeout → addInterceptor (loop) → build(). No pinning step exists.
Reproduce jadx -d out persona-wallet.apk && grep -rn "certificatePinner\|CertificatePinner" out/ – returns zero results

Decompiled source (lines 185–227, abbreviated):

public final OkHttpClient okhttpClient(...) {
    OkHttpClient.Builder builderAddNetworkInterceptor =
        new OkHttpClient.Builder().addNetworkInterceptor(new Interceptor() 💬);
    TimeUnit timeUnit = TimeUnit.MINUTES;
    OkHttpClient.Builder builderConnectTimeout = builderAddNetworkInterceptor
        .readTimeout(1L, timeUnit)
        .writeTimeout(1L, timeUnit)
        .connectTimeout(1L, timeUnit);
    Iterator it = set.iterator();
    while (it.hasNext()) {
        builderConnectTimeout.addInterceptor((Interceptor) it.next());
    }
    return builderConnectTimeout.build();
    // No certificatePinner() call anywhere in this chain.
}

SDKSeven Simultaneous Analytics Services

A user going through Persona verification is tracked by seven analytics services at the same time:

Service Platform Detail
Persona Telemetry Android + Web AES-encrypted events to tg.withpersona.com, 15 event types
Sentry (3 projects) Android + Web + Marketing 100% session tracing, user interaction tracking, view hierarchy capture
Amplitude Web Product analytics, behavioral tracking, conversion funnels
Datadog RUM Web Real User Monitoring, page loads, interactions, network requests
FingerprintJS v3.3.0 Web Device fingerprinting, contains ad network tracking URLs
Mixpanel Android Mobile product analytics
Firebase Analytics Android Google analytics integration

The Android SDK’s Sentry configuration sets io.sentry.traces.sample-rate = 1 (100% of sessions), io.sentry.traces.user-interaction.enable = true, and io.sentry.attach-view-hierarchy = true. Every user session is fully traced with interaction recording and UI hierarchy capture.

Primary source AndroidManifest.xml metadata from Persona Wallet APK v1.14.0 | jadx 1.5.5 | 2026-03-31
Source Decompiled AndroidManifest.xml elements
APK package com.withpersona.app.reusablepersonas v1.14.0
Sentry DSN ad039950...@o175220.ingest.us.sentry.io/4506939573993472
Reproduce jadx -d out persona-wallet.apk && grep -E "sentry|sample-rate|user-interaction|attach-view" out/resources/AndroidManifest.xml

Manifest entries:

io.sentry.dsn = https://ad039950...@o175220.ingest.us.sentry.io/4506939573993472
io.sentry.traces.sample-rate = 1           // 100% of sessions traced
io.sentry.traces.user-interaction.enable = true   // taps, clicks, gestures
io.sentry.attach-view-hierarchy = true            // full UI tree on errors

Sentry integration classes found in decompiled bytecode:

ActivityLifecycleIntegration    - tracks activity start/stop/resume/pause
FragmentLifecycleIntegration    - tracks fragment lifecycle
UserInteractionIntegration      - captures user taps and gestures
NetworkBreadcrumbsIntegration   - logs network connectivity changes
ViewHierarchyEventProcessor     - captures view hierarchy snapshots
io.sentry.android.replay.*     - session replay (record and replay user sessions)

Primary source Mixpanel and Firebase classes from Persona Wallet APK v1.14.0 | jadx 1.5.5 | 2026-03-31
Source Decompiled class files and .properties files from APK
APK package com.withpersona.app.reusablepersonas v1.14.0
Reproduce (Mixpanel) jadx -d out persona-wallet.apk && find out/ -path "*mx_com.mixpanel*" -name "*.java" | wc -l
Reproduce (Firebase) jadx -d out persona-wallet.apk && find out/ -name "firebase-*.properties"

Mixpanel SDK (repackaged as mx_com.mixpanel.android.mpmetrics):

Key classes found:
mx_com.mixpanel.android.mpmetrics.MixpanelAPI
mx_com.mixpanel.android.mpmetrics.AnalyticsMessages
mx_com.mixpanel.android.mpmetrics.MixpanelActivityLifecycleCallbacks
mx_com.mixpanel.android.mpmetrics.PersistentIdentity
mx_com.mixpanel.android.mpmetrics.SystemInformation
20+ files total. mx_com prefix = repackaged/embedded build.

SystemInformation collects:
- Device model, OS version, screen dimensions
- Mobile carrier name
- Bluetooth status
- NFC status

Firebase / Google Data Transport:

firebase-annotations.properties
firebase-components.properties
firebase-encoders-json.properties
com.google.android.datatransport.cct.internal.ClientInfo
Firebase component registrars loaded at startup

SDKSilent Network Authentication via Vonage

The SDK can silently verify a user’s phone number through the mobile carrier with zero user interaction. The PhoneNumberSna component uses Vonage (Ericsson subsidiary) to make an HTTP request over the device’s cellular connection. The carrier intercepts the request and verifies that the SIM card’s phone number matches the number encoded in the URL. The request follows up to 10 redirects through carrier authentication infrastructure. Results are auto-submitted to Persona’s backend with countdown=0, meaning the verification happens instantly. The user never sees, touches, or approves the carrier-level verification.

From the decompiled source: the PhoneNumberSnaComponent implements AutoSubmitableComponent. When verification completes, UiState.Displaying.AutoSubmit fires with countdown=0 and the form is submitted immediately.

Primary source Decompiled from Persona SDK sna-impl-2.35.2.aar | jadx 1.5.5 | 2026-03-31
File sna-impl-2.35.2.aar → VonageSnaClient.java (59 lines)
SHA-256 137a1d8aa0d77282bed76ec51b9851a24c554b429d36b7f3b7e4ba877f7766fb
APK package com.withpersona.app.reusablepersonas v1.14.0
Module files VonageSnaClient.java, VonageSnaClientFactory.java, VonageSnaResponse.java, GeneratedJsonAdapter.java (4 files total)
Reproduce jadx -d out persona-wallet.apk && grep -rn "VGCellularRequestClient\|startCellularGetRequest" out/

Decompiled source (key methods):

public VonageSnaClient(Context context, SilentNetworkAuthConfig config, Moshi moshi) {
    this.config = config;
    this.moshi = moshi;
    VGCellularRequestClient.Companion.initializeSdk(context);
}

public SnaClient.Response performSilentNetworkAuth() throws Exception {
    if (!SnaUtils.INSTANCE.isValidSnaCheckUrl(this.config.getCheckUrl())) {
        return new SnaClient.Response.Error(...);
    }
    JSONObject result = VGCellularRequestClient.Companion.getInstance()
        .startCellularGetRequest(
            new VGCellularRequestParameters(
                this.config.getCheckUrl(),   // URL from Persona server
                MapsKt.emptyMap(),            // headers
                MapsKt.emptyMap(),            // query params
                this.config.getMaxRedirects() // follows up to N carrier redirects
            ), false);
    // Carrier validates SIM -> returns success/failure JSON
}

SDKWebRTC Live Video Streaming

During selfie capture, the SDK streams live video to webrtc-consumer.withpersona.com via WebRTC TURN connections. The server receives continuous video, not just captured frames. An optional recordAudio flag enables audio recording during the stream. The SDK’s VideoCaptureMethod priority prefers Stream (WebRTC) first, falling back to Upload only if streaming is unavailable.

On-device face detection uses Google ML Kit to extract: bounding box, Euler angles (pitch, rotation, tilt), smile probability, left/right eye open probability, 10 face landmarks, and 15 face contour types. A 3×3 brightness grid divides the face region into 9 zones and computes per-zone luminance to detect flat paper or screen reflections. All anti-spoofing analysis is delegated to the server. The terms anti_spoof, active_liveness, passive_liveness, and depth do not appear in the SDK codebase.

SDKNFC Passport Chip Reading

The SDK implements ICAO 9303 BAC/PACE protocol for reading e-passport chips. Data groups read from the chip:

Data Group Contents
DG1 (MRZ) Name, nationality, document number, date of birth, expiry, sex
DG2 (Facial Photo) JPEG2000/JPEG facial biometric photo stored on the chip
DG14 (Chip Auth Keys) ChipAuthenticationPublicKeyInfo, ChipAuthenticationInfo
SOD (Security Object) Signed hashes of all data groups for tamper detection

The data groups are server-configurable via PassportNfcReaderConfig.enabledDataGroups. The server can request additional data groups at any time. Terminal Authentication (EAC-TA) is not implemented, meaning the passport chip cannot verify whether Persona is an authorized reader. Chip Authentication is supported but the absence of Terminal Authentication means the chip has no way to refuse data extraction.

43 Verification Types Across 14 Countries

The web inquiry bundle contains the complete Persona platform entity registry, expanding well beyond the February 2026 leak. 15 verification types were not present in the leaked source or the Android SDK:

Type System Country
VerificationDigitalIdWorldId Worldcoin/World ID (iris biometric) Global
VerificationDigitalIdFranceIdentite France Identite France
VerificationDigitalIdEDoApp eDoApp digital identity Estonia
VerificationDigitalIdFinnishTrustNetwork Finnish Trust Network Finland
VerificationDigitalIdIdin iDIN (banking ID) Netherlands
VerificationDigitalIdItsMe itsme digital ID Belgium/Netherlands
VerificationDigitalIdMitId MitID (national ID) Denmark
VerificationDigitalIdOneId OneID digital identity United Kingdom
VerificationDigitalIdSwedishBankId Swedish BankID Sweden
VerificationDigitalIdConnectId ConnectID Australia
VerificationCertificateKorea Korean certificate verification South Korea
VerificationBankPennydrop Bank account micro-deposit Universal
VerificationQesInfocert Qualified Electronic Signature (eIDAS) EU
VerificationVerifiableCredential W3C Verifiable Credential Universal
VerificationMdoc Mobile driver’s license (ISO 18013-5) US states

Persona now has integration with 15 digital identity systems across 14 countries, including Worldcoin’s iris biometric World ID. The platform also supports Aadhaar (India, 1.4 billion enrolled), Serpro (Brazil, 220 million), PhilSys (Philippines, 92 million), Singpass (Singapore), and ECBSV (US SSA Social Security number verification).

47 Report Types with 16 Third-Party Integrations

The web bundle reveals 47 distinct report types. The following third-party data integrations were not previously documented:

Integration Company Data
ReportChainalysisAddressScreening Chainalysis Crypto wallet sanctions screening
ReportCoinbaseCheckCryptoRisk Coinbase Cryptocurrency transaction risk
ReportEquifaxOneview Equifax Credit bureau data
ReportFinraBrokerCheck FINRA Securities broker/advisor check
ReportSecActionLookup SEC Securities enforcement actions
ReportSentilinkApplicationRisk Sentilink Synthetic identity fraud detection
ReportTrmWalletScreening TRM Labs Crypto compliance screening
ReportMxAccount MX Financial account aggregation
ReportKyckrBusinessLookup Kyckr Global company registry data
ReportMiddeskBusinessLookup Middesk Business entity verification

Persona connects to Chainalysis and TRM Labs for crypto wallet screening, Equifax for credit bureau data, FINRA and the SEC for securities enforcement, Sentilink for synthetic identity detection, MX for financial account aggregation, and Kyckr for global company registries. The platform processes far more than identity verification.

26 Government ID Types

The SDK supports 26 distinct government ID types, including country-specific documents: Japan MyNumber Card (myn), Singapore/Malaysia NRIC (nric), Philippines OFWID (ofw), Philippines UMID (umid), Philippines NBI Clearance (nbi), and India PAN Card (pan). US and Canadian driver’s licenses are parsed via an AAMVA PDF417 barcode reader that extracts 13 fields: first name, middle name, last name, sex, street address, city, state, postal code, ID number, issue date, expiration date, date of birth, and country.

Roblox: FacialAgeEstimation Module

Decompilation of the Roblox APK v2.714.1091 confirms the full Persona SDK is embedded under the internal module name com.roblox.universalapp.facialageestimation. The integration bridge at com.roblox.client.personasdk passes verification results through a JNI (Java Native Interface) bridge directly into Roblox’s C++ game engine. The DisablePauseSessionInPersonaFlow feature flag prevents users from pausing or backgrounding the app during verification, ensuring the continuous WebRTC video stream is not interrupted.

Roblox’s manifest includes permissions for camera, audio recording, NFC, biometric authentication, fingerprint, Bluetooth, and contacts (READ_CONTACTS, unusual for a game). The full 21-endpoint API surface and all surveillance capabilities documented above are available inside Roblox, an app where 67% of users are under 16.

SDKServer-Driven Architecture

The Persona client is a stateless renderer. The server dictates every step, every component, and every transition via 38 UI component types and 12 inquiry states. There is no hardcoded step sequence in the SDK. The server can dynamically insert, reorder, or skip any step for any user based on risk scoring, template configuration, or real-time decisions. This means the verification pipeline experienced by one user can be completely different from another, and users have no way to predict or audit what data collection steps will be triggered.

SDKAnti-Tampering and Debugger Detection

Every API request is signed with four obfuscated headers: NHMJLNRS (HMAC-SHA256 hash of JWT sub, timestamp, and request body), STPBWSBB (Unix timestamp), DNLGNZLZ (secondary hash incorporating header values), and TLJLGGDG (list of signed header names). A fifth header, VTDGJLGG, reports whether a debugger is attached to the process via Debug.isDebuggerConnected(). This flag is included in the signed header set, making it tamper-evident. Google Play Integrity verification runs with up to 5 retries and a 1-second delay between attempts.

All Analytics Keys Exposed and Active

The following keys are embedded in publicly served client-side code. All were confirmed active through testing:

Service Key/Identifier Status
AES Telemetry 4ERbfREmnh82jvK5QaXOv8jZ3OQq9hKg5o/Hbb3l9bk= Active (decryption verified)
Amplitude API 8f9fcc63055c35a7ba867e38e0738939 Active (ingested test event)
Sentry Web DSN key 233a1fa0... / project 5579484 Active
Sentry Marketing DSN key e4d8556f... / project 4508775074496512 Active
Sentry Android DSN key ad039950... / project 4506939573993472 Active
SDK Token F4SGT2MWWFC6NH5CUPY4LF2LVY Active

Sentry organization ID is o175220. All three Sentry DSNs map to the same organization. The web inquiry bundle also contains Datadog RUM application ID and client token, and an Osano CMP (consent management) account identifier.

Browser-Side Age and Gender Estimation

The web verification flow loads faceapi.js (1.3MB), which includes an age_gender_model for client-side age and gender estimation. This ML model runs in the browser before any data is sent to Persona’s servers. The document OCR module (microblink.js, 91KB) performs MRZ reading directly in the browser.

End-to-end data flow from user through Persona SDK to intelligence agencies

{💬|⚡|🔥} **What’s your take?**
Share your thoughts in the comments below!

#️⃣ **#Surveillance #Findings #Age #Verification #Mass #Surveillance #Infrastructure**

🕒 **Posted on**: 1775475506

🌟 **Want more?** Click here for more info! 🌟

By

Leave a Reply

Your email address will not be published. Required fields are marked *