- detect/PresenceEngine.kt: identity-agnostic streaming detector for key-rotating clones (novel-churn gate, seamless-handover chain, co-movement gate, coherence). Full design in docs/detection-rotation-clone.md. - Wired into ScanService as a parallel signal; CONFIRMED verdict raises a distinct rotating-tracker alert (softer tiers stay silent pending real-capture validation). - PresenceEngineTest: synthetic clone (moving -> CONFIRMED), stationary clone (gated), single real tracker + far-ambient (CLEAR). - CI now runs :app:testDebugUnitTest so the engine has behavioural verification, not just a compile check. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0187UiEtasyowhEBYs6s9iF5
31 KiB
VIGIL: On-Device Temporal Detection of Personal Location Trackers, Including Identity-Rotating Clones
Kara Zajac · Black Flag Intel Draft v0.1 · 2026-07-15 · working paper, accompanies the VIGIL reference implementation
Abstract
Consumer item-trackers — Apple AirTag, Tile, Samsung Galaxy SmartTag, and the Google Find My Device network — have become instruments of stalking: in a survey of intimate-partner-violence survivors, 44% of those stalked reported physical location tracking, with vehicles the most common hiding place. Every deployed countermeasure (Apple Tracker Detect, the iOS Find My and Android Unknown Tracker alerts, and the open-source AirGuard) shares a structural assumption: it keys on a device identity and alarms when the same identifier is seen repeatedly while moving with the victim. This assumption fails in two directions. It is spatial where the true signal is temporal; and it is defeated outright by identity-rotating clones — a commodity ESP32 firmware that cycles ~2,000 Find My keys (a fresh one every ~30 s) tracked a victim for five days while raising zero alerts on every tool tested.
We present VIGIL, an Android application that reframes the problem as temporal co-movement: not "is a tracker near me" but "has the same tracker been at enough of my distinct places, over enough time, while close enough to be on me." VIGIL contributes (1) a cross-ecosystem, fully on-device detector that parses five BLE wire formats and gates alerts on an RSSI proximity test that prior tools omit, together with a learned, on-device baseline that auto-trusts the trackers that live where the user lives; and (2) an identity-agnostic presence engine that detects rotating-key clones by the one thing identity churn cannot hide — an unbroken, coherent, co-moving RF presence — and a rotation-rate "squeeze" argument showing that running an identity detector and a churn detector together leaves no rotation rate that evades both. VIGIL holds no network permission: the tracker database, the learned baseline, and all inference run and remain on the device. We describe the per-ecosystem detection methodology, the temporal model, the presence engine, the implementation, and a proposed evaluation, and we are explicit about the adaptive-adversary floor below which single-session on-device detection is information-theoretically impossible.
1. Introduction
The same crowd-sourced location networks that help people find lost keys also let a motivated abuser find a person. Apple's Find My network turns a US$29 coin-sized beacon into a globe-spanning tracker that piggybacks on hundreds of millions of other people's iPhones; Google's Find My Device network does the same across the Android install base. Placed in a target's bag, coat, or car, such a beacon reports the target's location without any infrastructure of the attacker's own.
Platform vendors responded with unwanted-tracking alerts, and the security community produced AirGuard (TU Darmstadt), the best open-source detector. These tools work, in their measured evaluations, slowly and narrowly: an in-the-wild study found an iPhone took 5 h 41 m to alert on an AirTag (and only on reaching home Wi-Fi), never detected a Chipolo, and that Samsung's own app never found its own SmartTag. All of them share the same core algorithm — count repeat sightings of one BLE identifier; alarm past a threshold — and all of them inherit its two structural weaknesses:
- Spatial, not temporal. They reason about presence, so they need hand-tuned thresholds to avoid alarming on the many trackers legitimately around us. The discriminating fact — that a stalking tracker recurs across the victim's changing locations — is used only weakly.
- Identity-bound. Because they track an identifier, any tracker that rotates its identifier faster than the accumulation window is invisible. Positive Security's Find You clone exploits exactly this: ~2,000 pre-loaded Find My public keys, one broadcast every ~30 s, so every sighting looks like a brand-new device. In a five-day carry test it defeated iOS, Apple's Tracker Detect, and AirGuard's background detection.
VIGIL is built on the opposite premise. Where OVERWATCH (its sibling project) asks what is watching this place, VIGIL asks what has been with me — it is a temporal detector. Its contributions:
- A cross-ecosystem, on-device temporal detector. VIGIL parses Apple Find My, Google FMDN, Samsung SmartTag, Tile, and the unified DULT format, filters to the separated-from-owner state where signalled, and escalates a device only when it clears a co-movement test across the user's distinct geographic cells — gated by an RSSI proximity check that AirGuard omits, which rejects the "tracker in a passing car" false positive.
- A learned, on-device baseline. VIGIL learns the places a user dwells and auto-trusts trackers that recur there across days — the user's own AirTag, a partner's Tile — collapsing the dominant benign false-positive class without a server and without the user tagging anything.
- A presence engine for rotating clones. VIGIL detects the attack class that defeats every deployed tool, by abandoning identity tracking in favour of identity-agnostic presence continuity, and we give a squeeze argument (§5.4) that closes the evasion gap left by either detector alone.
- A privacy architecture with no network. VIGIL requests no
INTERNETpermission. There is no server, no account, and no telemetry.
We are equally explicit about what VIGIL cannot do (§5.6, §10): a patient, low-duty-cycle adaptive adversary can push detection from minutes-latency single-session to days-latency multi-session, and no on-device passive detector escapes that floor.
2. Background and threat model
2.1 BLE trackers and the separated state
An item-tracker is a Bluetooth-Low-Energy beacon. When near its owner it is connected or advertises a non-locatable payload; when separated from its owner it broadcasts a payload that any nearby "finder" phone can encrypt-and-upload to the vendor's network, letting the owner retrieve its location. Two facts make passive third-party detection possible at all:
- Only the separated state matters for stalking — a tracker with its owner is not following you — and separated trackers advertise loudly (every ~2 s).
- To be findable, separated trackers rotate their identifier slowly. The Apple/Google DULT specification, and each vendor's implementation, rotate the advertised address/key roughly once per 24 hours in the separated state (versus ~15 minutes near-owner). A separated AirTag holds one identity for a full day, re-rolling at 04:00 local. This slow rotation is deliberate — it is what lets a victim's phone recognise the same tracker over time — and it is the invariant the clone attack violates and that VIGIL's presence engine exploits.
2.2 Threat model
Adversary. Plants one or more trackers on the victim (bag, vehicle, clothing). May use (a) a genuine, unmodified tracker; (b) a genuine tracker with a physically disabled speaker; or (c) a modified/cloned emitter (custom firmware, rotating keys, silent). The adversary controls the tracker but not the victim's phone.
Defender. The victim's Android phone, running VIGIL, passively scanning BLE. It never transmits to or connects to the tracker for detection (an optional, user-initiated GATT "make it ring" is out of the passive path). It has no server.
Goal. Alert the victim, with useful latency and a tolerable false-positive rate, that a tracker is travelling with them — including when the tracker rotates its identity or is silent.
Non-goals. VIGIL does not track individuals, does not deanonymise tracker owners beyond the vendor-provided reactive flows, and does not claim to defeat a patient adaptive adversary in a single session (§5.6).
3. Per-ecosystem detection
VIGIL's scanner (scan/BleTrackerScanner.kt) runs a hardware-filtered BLE scan —
the controller wakes the app only on a signature match, which makes screen-off
scanning deliverable — and hands each match to a stateless parser
(scan/TrackerParser.kt) that recognises five wire formats. For each ecosystem we
describe (a) the on-air signature VIGIL matches, (b) how it reads the
separated state, and (c) the identity it keys on for temporal correlation.
3.1 Apple Find My / AirTag
Signature. BLE manufacturer-specific data under Apple company id 0x004C,
message type 0x12 (offline finding), payload length 0x19 (25 bytes). After
Android strips the two company-id bytes, the payload is
[type=0x12, length=0x19, status, key(22), keyTopBits, hint].
Separated state. The status byte carries a "maintained" bit (bit 2): set
when the owner was in range within the current rotation period, cleared when
separated. VIGIL treats a cleared/absent maintained bit as separated. (Setting the
status byte to 0x00 is a known first-party-alert-suppression trick, so VIGIL
does not treat the bit as ground truth for benign-ness — only for relevance.)
Identity. The advertised P-224 public key is the identity, and — uniquely — the BLE MAC is derived from the key, so both rotate together. VIGIL keys on a hash of the advertised key bytes, which is stable across the ~24 h separated epoch. The 04:00 re-roll intentionally severs continuity; §5 addresses bridging it.
3.2 Google Find My Device network (FMDN / "Find Hub")
Signature. BLE service data (AD type 0x16) under 16-bit UUID 0xFEAA (the
Eddystone UUID; pairing uses a different service, 0xFE2C). The first
service-data byte is the frame type.
Separated state. VIGIL reads it in cleartext: frame 0x40 = normal, frame
0x41 = unwanted-tracking/separated. A subtlety with defensive consequences: the
0x41 state is server-triggered — Google decides a tag has been separated
(~≥30 min) and a nearby Android device flips it. A freshly-separated stock tag is
therefore still rotating its EID (~every 1024 s) and MAC together and is not
passively re-linkable until flipped to 0x41, at which point the MAC freezes for
24 h. VIGIL keys FMDN identity on the MAC, valid within the separated epoch.
3.3 Samsung Galaxy SmartTag / SmartTag2
Signature. BLE service data under UUID 0xFD5A (the Samsung company id
0x0075 is emitted by all Samsung gear and is not tag-unique; the service UUID is
the anchor). A connectable/setup tag also exposes a smarttag device name.
Separated state. The first service-data byte encodes a 3-bit state (bits 5–7):
2 = lost (after 15 min), 3 = "overmature-lost" (after 24 h; triggers Samsung's
own anti-stalking), 4–6 = paired/connected. VIGIL treats states 2–3 as
separated. In overmature state the rotating privacy id becomes daily-static,
giving a ~24 h re-link window; in the first 24 h everything rotates every 15 min
and is not passively re-linkable.
3.4 Tile
Signature. BLE service data under 0xFEED (activated), 0xFEEC
(pre-activation), or the legacy 0xFE84.
Separated state. None. A Tile emits no separated/lost-state beacon — it is "always findable," advertising identically whether with its owner or lost.
Identity. Tile's decisive property: the BLE MAC is static and never rotates, in any state. This makes Tile the easiest ecosystem to correlate (an indefinite persistent key) but the one with no separated flag, so VIGIL treats every Tile as a live candidate and relies entirely on persistence + co-movement. Notably, Tile's "Anti-Theft Mode" — which hides a Tile from Tile's own Scan-and-Secure and from platform alerts — changes nothing at the BLE layer, so a third-party scanner such as VIGIL detects an anti-theft Tile identically to a normal one, closing a documented stalking gap.
3.5 DULT (unified, emerging)
Signature. BLE service data under UUID 0xFCB2.
Separated state. The near-owner bit is the least-significant bit of byte 14
(1 = near owner, 0 = separated); a Network-ID byte identifies the vendor
network. VIGIL parses this for forward compatibility as trackers migrate to the
unified format.
3.6 Partner tags and summary
Chipolo, Pebblebee, eufy, Motorola, Jio, and Rolling Square do not carry a
brand-specific signature: each SKU advertises as the network it was provisioned
to (Apple 0x004C/0x12 or Google FMDN 0xFEAA). VIGIL detects the network, not
the brand; legacy proprietary SKUs (classic Chipolo, original JioTag) join no
crowd network and are out of scope.
| Ecosystem | Signature | Separated signal | MAC rotation (separated) | Re-link window |
|---|---|---|---|---|
| Apple Find My | mfg 0x004C, type 0x12 |
status "maintained" bit cleared | ~24 h (re-roll 04:00), MAC = key | ~24 h |
| Google FMDN | svc data 0xFEAA, frame 0x41 |
cleartext frame 0x41 (server-gated) |
24 h once 0x41; else ~1024 s |
~24 h once separated |
| Samsung SmartTag | svc data 0xFD5A |
state byte 2/3 (lost/overmature) | 24 h once overmature; else 15 min | ~24 h once overmature |
| Tile | svc data 0xFEED/0xFEEC |
none (always findable) | none — static MAC | indefinite |
| DULT (unified) | svc data 0xFCB2 |
byte-14 LSB = 0 | ~24 h separated | ~24 h |
4. The temporal co-movement model
4.1 The reframing
A tracker being near a user is uninformative — modern environments are saturated with them. The stalking signal is persistence across the user's own changing locations: because the phone is (almost) always on the user, counting a tracker's presence across the user's distinct places over time is the co-movement measure, and it needs no second trajectory.
4.2 The test
Each parsed sighting is geotagged with a coarse fused-location fix and written to
an on-device store (data/db/VigilDatabase.kt) as (trackerId, timestamp, rssi, separated, lat, lon, geohash7), retained 14 days. Over the trailing 24 h a
tracker is scored on:
- Effective sightings — raw sightings debounced to at most one per 15 min, so a 2 s-interval beacon cannot trivially inflate the count. Require ≥ 3.
- Distinct places — the number of distinct geohash-7 cells (~153 m) among its sightings. Require ≥ N, with N = 2/3/4 by sensitivity (high/medium/low).
- Span — first-to-last minutes. Require ≥ T, with T = 30/45/90 min.
- RSSI proximity gate — the smoothed peak RSSI must at least once cross an on-body/in-bag floor (−90/−85/−80 dBm by sensitivity). This is the piece AirGuard omits, and it is what distinguishes a tracker on the user from one that merely shared a road with them at two lights.
A device escalates OBSERVED → SUSPICIOUS → ALERTING (detect/CoMovementEvaluator.kt).
ALERTING requires all four conditions; SUSPICIOUS requires repeated close sightings
without yet enough spatial/temporal spread. Non-separated (near-owner) sightings
never escalate. These thresholds are adapted from AirGuard's field-tuned model
(≥3 sightings, N distinct locations ≥150 m apart, T minutes) with the added RSSI
gate.
4.3 The learned baseline and the allowlist
Two trust signals suppress the dominant benign class — the trackers that belong in the user's life.
- Allowlist. The user marks a tracker "This is mine"; it never alerts again.
- Learned baseline (
detect/BaselineManager.kt). VIGIL counts location-tagged sightings per geohash-6 cell; a well-visited cell becomes an anchor (home, work). A tracker seen at an anchor on ≥ 3 distinct calendar days is auto-marked baseline-safe and excluded from alerting. This learns "the AirTag that is always in my house" without a server and without the user labelling anything. (The current visit-count anchor heuristic is a v1; the roadmap replaces it with stay-point/dwell clustering.)
5. The rotation-clone presence engine
This section addresses the attack class that defeats every deployed detector, and
is the paper's core modeling contribution. The full design is in
docs/detection-rotation-clone.md; we summarise the argument here.
5.1 The attack and why identity detectors fail
The Find You clone is one physical ESP32 radio that broadcasts a pool of ~2,000 Apple Find My public keys, cycling to a new one every ~30 s. To any identity-keyed detector each key is a new device seen once, so the "same identifier ≥ 3 times" counter never accumulates and the detector stays silent — measured at zero alerts over five days.
5.2 The exploitable invariant
The defence begins with a standards fact: DULT, Apple, and Google mandate ~24 h rotation in the separated state. A legitimate separated tracker therefore holds one identity for a full day; a clone rotating every 30 s runs ~2,880× faster than any specification-compliant device. This is not a heuristic "that seems suspicious" — it is a categorical violation of a standardised invariant, giving a clean anomaly baseline.
5.3 Presence, not identity
VIGIL stops tracking who is present and starts tracking whether one radio is continuously present. A rotating clone, to function as a tracker, must emit an unbroken stream of separated-state beacons at roughly stable close-range RSSI that moves with the victim across locations where the ambient tracker population fully turns over. We formalise three identity-agnostic quantities:
- Novel-identifier churn rate
λ_novel— the rate of never-before-seen separated identities (over a 5-min window against a 30-min novelty set). A real separated tracker ≈ 0.0007/min; the clone ≈ 2/min. - Presence continuity — the duty cycle with which some separated beacon occupies the close band (RSSI ≥ ~−65 dBm), and the longest unbroken run.
- Seamless-novel-handover chain — the number of times the close-band identity
changes to a novel id with no RSSI discontinuity (
|Δrssi| ≤ 8 dB) and no time gap (Δt ≤ 6 s). One physical radio produces a long chain of such seamless handovers; a crowd of many radios at many distances produces gappy, RSSI-discontinuous handovers. This chain is the tell no amount of identity churn can fake while remaining a functioning tracker.
The physics that make co-movement a hard discriminator: a static tag or an
independently-moving passer can remain in the close band (radius R ≈ 10 m) for at
most 2R / v_rel — ≈ 1.5 s at driving speed. Only a co-moving emitter (relative
velocity ≈ 0) has unbounded dwell. So a close-band presence sustained across ≥ 3
distinct cells while the user is moving cannot be explained by any single
ambient source.
5.4 The pipeline and the squeeze
A three-stage streaming pipeline (all O(1)-ish per sighting, on-device): a CUSUM
change-point on λ_novel versus a rolling personal baseline triggers an
identity-agnostic presence-track confirmer (counting seamless novel handovers
and RSSI coherence), which alarms only behind a hard co-movement gate (net
displacement ≥ 500 m across ≥ 3 cells while moving).
The robustness argument is the rotation-rate squeeze. VIGIL runs the classic identity detector (which catches any identity persisting > ~3–5 min) and the churn detector (which catches sustained novel-churn above ~0.5–1/min) simultaneously:
rotation period: 30 s ─── 2 min ─── 5 min ──────────── 24 h
└ churn path catches ┘
└ overlap ┘
└────── identity path catches ──────┘
No rotation period evades both. Fast rotation is caught by churn; slow rotation
by identity; the middle by both. Moreover the presence-continuity path is
rotation-rate-agnostic — slowing rotation lowers λ_novel but does nothing to
the unbroken coherent co-moving track. The adversary's only real lever is
continuity, not rate.
5.5 False positives
The engine's viability rests on dense-urban and transit false positives. Four
discriminators, strongest first: (1) the seamless-handover chain — a crowd is
many radios and cannot fake one continuous (t, rssi) track across 500 m; (2)
co-movement across turnover — bounded ambient dwell means a presence spanning
≥ 3 non-adjacent cells is not any single source; (3) RSSI coherence — one
radio yields a smooth RSSI random-walk, a crowd a high-variance cloud; (4)
stationary suppression — no motion, no alarm, which removes the entire
apartment/at-home class. The genuinely hard case is live rush-hour transit,
where boarding churn, vehicular co-movement, and continuous occupancy align. The
resolution is a mode-change gate: a transit crowd cannot follow the victim
off the train and down the street, so escalation to a hard alert is withheld
until the coherent co-moving presence survives a detected context transition. This
trades latency for transit-FP suppression — a deliberate, disclosed choice,
not a false alarm.
5.6 The honest floor
Every evasion degrades the adversary's own tracker (slower/duty-cycled rotation and reduced TX power mean fewer, coarser location fixes). Below some duty cycle — a few randomly-timed, random-power beacons per 15 min — the emitter becomes information-theoretically indistinguishable, within a single session, from sparse ambient pass-bys, and detection must move to cross-session recurrence (the same anomalous weakly-co-moving presence recurring day after day along the victim's routes), which costs days of latency and requires opt-in persistent storage. This is the honest floor: a patient, low-duty-cycle adaptive adversary forces VIGIL from minutes-latency single-session detection to days-latency multi-session detection. VIGIL states this rather than claiming an impossible guarantee.
6. Implementation
VIGIL is a native Android/Kotlin app (min SDK 26), reusing the scanning and service architecture of OVERWATCH.
scan/TrackerSignatures.kt BLE hex signatures for every ecosystem
scan/TrackerParser.kt ScanResult -> TrackerObservation (five wire formats)
scan/BleTrackerScanner.kt hardware-filtered scan (screen-off capable)
service/ScanService.kt foreground service; geotags, persists, alerts, vibrates
data/db/VigilDatabase.kt Room: trackers, 14-day sightings, baseline places
data/TrackerRepository.kt ingest + baseline + evaluate on each sighting
detect/CoMovementEvaluator the co-movement test + RSSI proximity gate
detect/BaselineManager.kt anchor-place learning -> auto-trust household tags
detect/PresenceEngine.kt the rotation-clone engine of §5 (v1, unit-tested)
Privacy properties. The manifest declares no INTERNET permission; VIGIL
cannot open a socket. All state — trackers, sightings, baseline, inference — lives
in an on-device SQLite database and never leaves the phone. BLUETOOTH_SCAN is
declared without neverForLocation, because detection is intentionally
location-correlated (and because that flag would filter out the very beacon-shaped
advertisements VIGIL parses). VIGIL only listens: it never advertises, probes, or
connects to a tracker on the detection path.
7. Proposed evaluation
VIGIL is a prototype; the following methodology is specified but not yet executed, and no detection-rate claims are made here.
- Red-team emitter. A parameterised OpenHaystack/Find You ESP32 clone with sweepable rotation period (30 s … 24 h), TX-power variance, and duty cycle. Carried, it is a real co-moving emitter — ground-truth positive without endangering anyone.
- Ambient baselines. Raw sighting logs across environment classes (rural drive, suburban, dense-urban walk, bus, rush-hour subway, highway, apartment block, crowd), each with paired emitter-on/off runs.
- Record/replay harness. The presence engine is a pure
List<Sighting> → List<ScoredEvent>function; ambient logs are recorded once and replayed to tune thresholds deterministically and offline in Kotlin, and attack-in-context scenarios are synthesised by merging clean and emitter-only traces. - Metrics. True-positive rate at a fixed false-positive budget (headline: TPR at ≤ 1 FP per active-carry-day, per class); detection latency (attach → first alert); ROC/AUC; robustness curves versus rotation period, TX power, and duty cycle; and ablations isolating each discriminator.
8. Comparison to prior art
| Capability | Apple Tracker Detect | iOS / Android built-in | AirGuard | VIGIL |
|---|---|---|---|---|
| Cross-ecosystem | Find My only | AirTag + FMDN + DULT partners (not Tile) | yes | yes |
| Background / automatic | no (manual scan) | yes | yes | yes |
| Fully on-device / no account | yes | yes | yes | yes (no network permission) |
| RSSI proximity gate on alerts | no | undisclosed | no | yes |
| Learned baseline (auto-trust) | no | no | manual ignore only | yes |
| Detects rotating-key clones | no | no | no | designed (§5) |
| Covers Tile anti-theft | no | no | yes (static MAC) | yes |
| Survivor-grade evidence export | no | no | limited | roadmap |
Cross-ecosystem, offline operation, and temporal co-movement are not novel — AirGuard has them. VIGIL differentiates on the pieces AirGuard's architecture forecloses: the RSSI gate, the learned baseline, and above all the identity-agnostic presence engine that targets the clone attack.
9. Privacy and ethics
VIGIL is a defensive, survivor-oriented tool. It maps and reasons about trackers, never about people, and holds no network to which anything could be exfiltrated. The learned baseline is a privacy feature — it exists so the app does not need to phone home to know which tags are "normal." The dual-use surface (BLE parsing that could in principle be repurposed for tracking) is mitigated by the passive-only, no-transmit, no-network design. As with all anti-stalking tools, VIGIL should be paired with survivor-safety guidance: a detected tracker can indicate an abuser with physical access, and "make it ring / remove the battery" advice must be given with situational-safety caveats.
10. Limitations
- Single-session floor (§5.6). A patient low-duty-cycle adaptive adversary is only detectable across sessions.
- Near-owner and freshly-separated tags are not passively re-linkable (Apple
near-owner; default FMDN before the
0x41flip; Samsung in the first 24 h). - Wire-format offsets are drawn from published reverse-engineering and, for SmartTag2 and 2024+ Tile, inferred from older captures; they require empirical validation before production trust.
- Background scan latency is bounded by Android's ~15-min background floor absent a persistent foreground service; motion-triggered scanning (roadmap) reduces it.
- Not yet evaluated. §7 is a plan, not a result.
11. Related work
Heinrich et al. reverse-engineered Apple Find My ("Who Can Find My Devices?", PETS 2021) and built AirGuard ("Protecting Android Users from Stalking Attacks by Apple Find My Devices", WiSec 2022), later measuring real-world stalking prevalence and detector efficacy ("Please Unstalk Me", PETS 2024). Mayberry/Shafqat et al. ("Who Tracks the Trackers?" / "Track You", PETS 2023) analysed AirTag anti-stalking timing. Yu et al. (USENIX Security 2024) reverse-engineered Samsung SmartTag, and Georgia Tech (2025) analysed Tile's static-MAC linkability. Bräunlein/Positive Security demonstrated the rotating-key clone ("Find You"). Naturalistic evaluations ("Stop Following Me!", EuroUSEC 2024) found deployed detectors rarely useful. The Apple/Google DULT IETF effort standardises the separated-state signalling and a baseline detection algorithm. VIGIL builds directly on this line and extends it to the identity-rotating adversary that all of it currently misses. Change-point detection (Page 1954; Basseville & Nikiforov 1993) and bounded-memory distinct counting (Datar et al.; Flajolet et al.) underpin the presence engine; the identity-free "sustained close presence" reasoning is anticipated by contact-tracing designs (DP-3T; Google/Apple Exposure Notification).
12. Conclusion
The anti-stalking detectors people rely on are spatial where the threat is temporal, and identity-bound where the adversary can rotate identities. VIGIL reframes detection as temporal co-movement, adds the proximity gate and learned baseline that make that reframing practical on-device and private, and introduces a presence engine that detects the rotating-key clone by the one property it cannot hide. The rotation-rate squeeze shows the combination leaves no safe rotation rate; the honest floor shows where even this stops. We release VIGIL as a working prototype and an open design, and invite the empirical evaluation §7 lays out.
References
- A. Heinrich, M. Stute, T. Kornhuber, M. Hollick. "Who Can Find My Devices? Security and Privacy of Apple's Crowd-Sourced Bluetooth Location Tracking System." PoPETs 2021. https://petsymposium.org/popets/2021/popets-2021-0045.pdf
- A. Heinrich, N. Bittner, M. Hollick. "AirGuard — Protecting Android Users from Stalking Attacks by Apple Find My Devices." ACM WiSec 2022. https://arxiv.org/pdf/2202.11813 · code: https://github.com/seemoo-lab/AirGuard
- A. Heinrich, L. Würsching, M. Hollick. "Please Unstalk Me: Understanding Stalking with Bluetooth Trackers and Democratizing Anti-Stalking Protection." PoPETs 2024. https://petsymposium.org/popets/2024/popets-2024-0082.pdf
- N. Shafqat et al. "Track You: A Deep Dive into Safety Alerts for Apple AirTags." PoPETs 2023. https://petsymposium.org/popets/2023/popets-2023-0102.pdf
- T. Yu et al. "Analyzing the Security of Samsung SmartTag." USENIX Security 2024. https://arxiv.org/pdf/2210.14702
- Kumar, Raymaker, Specter. Tile protocol analysis. 2025. https://arxiv.org/html/2510.00350v1
- F. Bräunlein / Positive Security. "Find You: Building a stealth AirTag clone." https://positive.security/blog/find-you · https://github.com/positive-security/find-you
- A. Catley. "AirTag reverse engineering." https://adamcatley.com/AirTag.html
- IETF DULT WG. "Detecting Unwanted Location Trackers" (accessory-protocol; threat-model). https://datatracker.ietf.org/wg/dult/
- Google. "Find My Device network (Fast Pair FMDN) specification." https://developers.google.com/nearby/fast-pair/specifications/extensions/fmdn
- SEEMOO-Lab. "OpenHaystack." https://github.com/seemoo-lab/openhaystack
- "Stop Following Me! Evaluating the Effectiveness of Anti-Stalking Features." EuroUSEC 2024. https://arxiv.org/abs/2312.07157
- E. S. Page. "Continuous Inspection Schemes." Biometrika 41, 1954. (CUSUM.)
- M. Basseville, I. Nikiforov. Detection of Abrupt Changes: Theory and Application. 1993.
- M. Datar, A. Gionis, P. Indyk, R. Motwani. "Maintaining Stream Statistics over Sliding Windows." SODA 2002.
This working paper accompanies the VIGIL reference implementation. The rotation-clone
engine (§5) is specified in docs/detection-rotation-clone.md and implemented as a
first version in detect/PresenceEngine.kt (unit-tested against synthetic clone/ambient
traces) and wired into the scan service; field-tuning against real captures remains.