One-Click Persistent Screen Recording Hijack via Session Replay SDK Backdoor
The Risk
Tapping a single link permanently redirected screen recordings from a retail company's Android app to an attacker's server. The recordings were picture-by-picture captures of everything the user saw in the app: the login screen with their password visible, the payment screen with their card number and security code visible, their addresses, their order history. The redirect survived closing the app, restarting the phone, and reopening the app. It stopped only when the user reinstalled the app from scratch. One link, sent by email or SMS or hidden in an ad, could compromise thousands of customers at once.
The Vulnerability
The retail app bundled a popular third-party session replay SDK. The SDK registered an exported deep link activity with no permission guard. The activity accepted a custom URI scheme reachable from any browser or app on the device. Inside the activity, the SDK checked the URL parameters for two hardcoded strings, a leftover developer-mode backdoor, and on match wrote arbitrary key-value pairs from a configure URL parameter directly into the SDK's persistent storage.
Two of those keys were critical. The first overrode the endpoint where session recordings were uploaded. The second disabled input-field masking, so passwords, card numbers, and security codes appeared in plaintext inside the recordings. The SDK read both values on every cold start. If the override was present, recordings were sent to the override URL instead of the SDK vendor's real servers.
The Attack
- Victim receives a link via email, SMS, QR code, or an ad on a web page.
- Victim taps the link. The retail app briefly flashes open as the deep link handler processes the parameters and writes the attacker's upload URL into the SDK's persistent storage. Under one second of visible activity.
- Victim uses the app normally. Every screen they view is captured as a sequence of image frames, gzip-compressed, and uploaded to the attacker's server instead of the SDK vendor's server.
- The redirect persists across app restarts, phone reboots, and force-stop cycles. It stops only on reinstall or clearing app data.
Proof-of-concept monitoring at the attacker-side server recorded full-frame screenshots of the login screen with email and password visible, the payment screen with card number, cardholder name, expiry, and security code in plaintext, and dozens of category and account screens across a normal browsing session. The test ran on both rooted and stock Play Store devices with identical results.
Persistence
The override URL lived in the SDK's SharedPreferences file, which is persistent app storage. Reading the file directly before and after the deep link confirmed the expected state change: the attacker URL present, masking disabled, force-start flag set. Restarting the app re-read the same values. The original vendor endpoint was never queried again.
The Impact
Every screen the victim viewed in the app was uploaded to the attacker server as actual image frames, not abstract event logs. The recordings contained:
- Login email and password fields in plaintext because masking was disabled by the deep link.
- Full payment screens with card number, cardholder name, expiry, and security code visible.
- Account pages showing delivery addresses, phone numbers, order history, and loyalty data.
- A persistent per-victim identifier in the upload metadata, so sessions could be linked across days.
At scale, a single SMS or email campaign would compromise any user who tapped the link, and every subsequent app session would continue to exfiltrate screen recordings until the user happened to reinstall the app. There was no in-app signal to the victim that anything had changed.
Remediation
- Mark the SDK's deep link activity as not exported, or add a signature-level permission guard. External apps and browsers have no reason to reach it.
- Remove the hardcoded developer backdoor credentials from production builds. Debug and developer tooling should not ship to end users.
- Strip the
configureURL parameter handler entirely from release builds. Arbitrary key-value writes from URL parameters is a critical design flaw. If developer tooling is required, gate it behind a build-time debug flag. - At the SDK level, reject any recording upload endpoint that does not match the vendor's own domains. This is a vendor-side fix that protects every app that ships the same SDK.
- Enforce input masking policy from server-side configuration, not from a flag writable by deep link.