Files
VIGIL/paper/vigil.md
T
Kara Zajac 0fa6a2dd2a Add technical paper + link from README
paper/vigil.md: per-ecosystem detection methodology (Apple/FMDN/Samsung/Tile/DULT) and the rotation-clone presence engine (identity-agnostic detection, the rotation-rate squeeze, FP analysis, honest floor). Draft working paper accompanying the reference implementation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0187UiEtasyowhEBYs6s9iF5
2026-07-15 00:24:18 -04:00

551 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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:
1. **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.
2. **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 `INTERNET`
permission. 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:
1. Only the **separated** state matters for stalking — a tracker with its owner is
not following *you* — and separated trackers advertise loudly (every ~2 s).
2. 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 57):
`2` = lost (after 15 min), `3` = "overmature-lost" (after 24 h; triggers Samsung's
own anti-stalking), `4``6` = paired/connected. VIGIL treats states 23 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 > ~35 min) *and* the
churn detector (which catches sustained novel-churn above ~0.51/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 (next) the rotation-clone engine of §5
```
**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 `0x41` flip; 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
1. 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
2. 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
3. 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
4. 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
5. T. Yu et al. "Analyzing the Security of Samsung SmartTag." *USENIX Security* 2024. https://arxiv.org/pdf/2210.14702
6. Kumar, Raymaker, Specter. Tile protocol analysis. 2025. https://arxiv.org/html/2510.00350v1
7. 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
8. A. Catley. "AirTag reverse engineering." https://adamcatley.com/AirTag.html
9. IETF DULT WG. "Detecting Unwanted Location Trackers" (accessory-protocol; threat-model). https://datatracker.ietf.org/wg/dult/
10. Google. "Find My Device network (Fast Pair FMDN) specification." https://developers.google.com/nearby/fast-pair/specifications/extensions/fmdn
11. SEEMOO-Lab. "OpenHaystack." https://github.com/seemoo-lab/openhaystack
12. "Stop Following Me! Evaluating the Effectiveness of Anti-Stalking Features." *EuroUSEC* 2024. https://arxiv.org/abs/2312.07157
13. E. S. Page. "Continuous Inspection Schemes." *Biometrika* 41, 1954. (CUSUM.)
14. M. Basseville, I. Nikiforov. *Detection of Abrupt Changes: Theory and Application.* 1993.
15. 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 fully specified in `docs/detection-rotation-clone.md` and is designed
but not yet wired into the shipping build.*