Pairing token travels in cleartext, lands in cloud backups and never rotates #3
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The pairing token is a long-lived secret that grants full control of the TV, but it is exposed on three fronts:
Cleartext on the wire.
Pairing.pairingUrl()buildshttp://<ip>:8765/?t=<token>and the manifest setsandroid:usesCleartextTraffic="true"(AndroidManifest.xml:18). The initialGET /?t=…is plaintext; thehistory.replaceStatein the remote page only scrubs the address bar afterwards, not what was already transmitted. Any passive observer on the same Wi-Fi (open network, or WPA2 without client isolation — common on consumer routers) captures it.Cloud backup.
android:allowBackup="true"(AndroidManifest.xml:14) with the token stored in SharedPreferences (Pairing.kt) means it is included in Android Auto Backup to Google Drive. Anyone with access to that Google account — a family member, a later owner of a reset device, a compromised account — recovers the token offline, without ever touching the TV.No rotation. The token is generated once and persisted forever. There is no way to revoke a leaked one short of clearing app data.
Cleartext is also process-wide rather than scoped to the LAN control channel, since there is no
network_security_config.xml.Suggested fix
android:dataExtractionRules/fullBackupContent), or setallowBackup="false"Found by multi-agent code review; verified against current manifest and
Pairing.kt.Fixed in
dd612fc, shipped in v0.9.0 — with one deliberate exception noted below.res/xml/backup_rules.xmlandres/xml/data_extraction_rules.xmlexcludepairing.xmlandauth.xmlfrom both cloud backup and device transfer, wired up in the manifest. The pairing token and the OIDC tokens no longer leave the device.Pairing.reset()drops the QR token, the four-digit code and every session token at once; it is reachable as "Kopplung zurücksetzen" in the settings, and the QR/code redraw immediately afterwards. Code-authenticated clients now hold their own session tokens (see #2), so a single phone can be cut off by resetting rather than being stuck with the master credential forever.MessageDigest.isEqual.Deliberately unchanged:
usesCleartextTraffic. Restricting it would need a network security config, and Android's config cannot express "any private address range" — only concrete hosts. Since the whole point of the generic source is pointing the TV at an arbitrary LAN server without TLS (ErsatzTV, Threadfin, a local Dispatcharr), scoping it would break legitimate setups without a workable allow-list. The token exposure that mattered is now bounded instead: it can be revoked, and it no longer travels to Google's backup servers.