Background
When the receiver processes a transition message and ratchets to a new routing token T_new, the polling loop immediately follows the chain and polls T_new within the same poll call (up to MAX_TOKEN_FOLLOWS_PER_POLL = 5 times). This means the server sees the same client IP poll T_old and then T_new in rapid succession, creating a deterministic IP-level linkage across epoch transitions.
This is a specific instance of the IP-correlation limitation already admitted in §2.3/§7.3, but it's worth calling out separately because token rotation is designed to prevent cross-epoch correlation — and the follow-chain largely undoes that at the IP layer.
Options considered
-
Delay to next scheduled cycle unconditionally. Never follow tokens within a single poll call; always wait for the next scheduled cycle. Cleanest from a privacy standpoint, but costs up to one full poll interval (~60s) of latency on every epoch transition. Bad UX when the user is actively watching and Alice has sent multiple updates since the last poll — the user won't see the latest location until the next cycle.
-
Delay to next scheduled cycle if backgrounded; follow immediately if foregrounded. Helps the common case (most polling happens in the background). Requires reliable foreground/background detection threaded into the shared KMP polling logic, which currently has no app-lifecycle awareness. On iOS in particular, "background" for a location app is nuanced.
-
Jitter the follow. Wait a random delay (0–30s) before polling T_new. Weakens the deterministic linkage without always paying a full cycle. Doesn't help if the IP is stable throughout.
-
Accept as a known limitation. Token rotation already provides content-layer unlinkability. The IP linkage only matters for an adversary tracking a specific user's IP over time, which is already an admitted limitation. The incremental improvement from delaying token follows is marginal for most real-world threat models.
Current thinking
Option 2 is probably the right long-term answer but requires foreground detection in shared code. Option 4 (accept the limitation) is the pragmatic near-term choice given the implementation complexity and the fact that §7.3 already admits IP correlation. Option 1 is too costly to UX.
Tracking here so we can revisit when/if foreground state becomes available to the shared polling layer.
References
- §2.3 / §7.3 (IP correlation admitted limitation)
- §12.3 (cross-epoch correlation — content-layer only)
LocationClient.kt — pollFriend token-follow loop, MAX_TOKEN_FOLLOWS_PER_POLL
Background
When the receiver processes a transition message and ratchets to a new routing token T_new, the polling loop immediately follows the chain and polls T_new within the same poll call (up to
MAX_TOKEN_FOLLOWS_PER_POLL = 5times). This means the server sees the same client IP poll T_old and then T_new in rapid succession, creating a deterministic IP-level linkage across epoch transitions.This is a specific instance of the IP-correlation limitation already admitted in §2.3/§7.3, but it's worth calling out separately because token rotation is designed to prevent cross-epoch correlation — and the follow-chain largely undoes that at the IP layer.
Options considered
Delay to next scheduled cycle unconditionally. Never follow tokens within a single poll call; always wait for the next scheduled cycle. Cleanest from a privacy standpoint, but costs up to one full poll interval (~60s) of latency on every epoch transition. Bad UX when the user is actively watching and Alice has sent multiple updates since the last poll — the user won't see the latest location until the next cycle.
Delay to next scheduled cycle if backgrounded; follow immediately if foregrounded. Helps the common case (most polling happens in the background). Requires reliable foreground/background detection threaded into the shared KMP polling logic, which currently has no app-lifecycle awareness. On iOS in particular, "background" for a location app is nuanced.
Jitter the follow. Wait a random delay (0–30s) before polling T_new. Weakens the deterministic linkage without always paying a full cycle. Doesn't help if the IP is stable throughout.
Accept as a known limitation. Token rotation already provides content-layer unlinkability. The IP linkage only matters for an adversary tracking a specific user's IP over time, which is already an admitted limitation. The incremental improvement from delaying token follows is marginal for most real-world threat models.
Current thinking
Option 2 is probably the right long-term answer but requires foreground detection in shared code. Option 4 (accept the limitation) is the pragmatic near-term choice given the implementation complexity and the fact that §7.3 already admits IP correlation. Option 1 is too costly to UX.
Tracking here so we can revisit when/if foreground state becomes available to the shared polling layer.
References
LocationClient.kt—pollFriendtoken-follow loop,MAX_TOKEN_FOLLOWS_PER_POLL