Device & Location Tracking
Phones, wearables, and laptops continuously emit radio signals that create persistent location tracking surfaces — even when apps are not visibly active. This guide covers the full spectrum of device-based tracking vectors and practical countermeasures.
Always-On Tracking
Comprehensive Tracking Vectors
| Vector | Signal Type | Range | Persistence | Mitigation |
|---|---|---|---|---|
| Cell towers | IMSI/IMEI registration | City-block (urban), km (rural) | Always (while powered on) | Airplane mode, Faraday bag |
| Wi-Fi probes | 802.11 probe requests | ~100m | When Wi-Fi enabled + scanning | Disable Wi-Fi when mobile, MAC randomization |
| BLE advertisements | Bluetooth Low Energy beacons | ~50m | Continuous (wearables, trackers) | Disable BLE, scan for stalker devices |
| GPS/GNSS | Satellite positioning | Global (receive only) | When apps request location | Disable location services per app |
| Ad ID / IDFA | Software identifier | N/A (transmitted via network) | Per app session | Reset/disable advertising ID |
| SDK telemetry | Background data exfiltration | N/A (transmitted via network) | Continuous (hidden) | App audit, firewall rules, DNS blocking |
| IMSI catcher | Cell-site simulator | ~2km | Targeted (law enforcement) | SnoopSnitch, avoid 2G fallback |
Modern Tracking Threats
BLE Item Networks
Apple Find My (2B+ devices), Samsung SmartThings Find, Tile, and Google Find My Device create massive mesh networks that can track any BLE beacon placed near a target.
Defense: AirGuard app, periodic BLE scans, tracker auditing
Retail Presence Analytics
Retailers deploy Wi-Fi probe collectors and BLE beacons to track foot traffic, dwell time, and repeat visits. These can be correlated with purchase data and loyalty programs.
Defense: Disable Wi-Fi/BLE in stores, use cash payments
SDK Telemetry Leakage
Analytics SDKs embedded in apps (X-Mode, Placer.ai, SafeGraph) transmit precise location data to data brokers — often without clear user consent or awareness.
Defense: App permissions audit, DNS-level blocking, minimal apps
Cross-Device Graphing
Browsers, wearables, smart home devices, and app accounts are fused into a single identity graph linking all your devices to one movement profile.
Defense: Account separation, different browsers per context
Device Hardening Playbook
Step 1: Radio Audit
- • Disable Wi-Fi and BLE when not actively needed
- • Enable MAC address randomization (Settings > Wi-Fi > Privacy)
- • Remove saved Wi-Fi networks you no longer use
- • Disable "Wi-Fi scanning" and "BLE scanning" in Developer Options
Step 2: App Permissions
- • Review all app location permissions (background → while using → never)
- • Disable "Precise Location" for non-navigation apps
- • Reset advertising ID monthly (or disable entirely)
- • Remove apps with known telemetry SDKs
Step 3: Tracker Defense
- • Install AirGuard (Android) for unknown tracker detection
- • Enable Apple's built-in AirTag safety alerts (iOS)
- • Run periodic manual BLE scans in vehicles and bags
- • Check for unknown BLE devices after visits to unfamiliar locations
Step 4: DNS Protection
- • Use DNS-level ad/tracker blocking (NextDNS, Pi-hole, AdGuard DNS)
- • Block known telemetry domains at router level
- • Monitor DNS queries for unexpected analytics domains
- • Use encrypted DNS (DoH/DoT) to prevent ISP tracking
Step 5: Cellular Hardening
- • Force LTE/5G only (disable 2G fallback to prevent IMSI catchers)
- • Consider prepaid SIM separation for high-risk activities
- • Use VPN on cellular to prevent carrier content inspection
- • Disable carrier-specific location services
Step 6: Ongoing Monitoring
- • Re-audit after every OS and app update
- • Monitor for newly added app permissions
- • Run weekly BLE tracker scans on vehicles
- • Review network traffic logs for unexpected connections
BLE Tracker Detection
Scan for unknown BLE beacons that may be tracking your movement.
#!/bin/bash
# Prerequisites: apt install bluez (provides hcitool, btmon)
# Platform: Linux only — macOS alternative: use nRF Connect app; Windows: use Bluetooth LE Explorer
# Comprehensive BLE tracker detection scan
# Detect AirTags, Tile, SmartTag, and unknown BLE beacons
# Quick scan for active BLE advertisers
sudo hcitool lescan --duplicates 2>/dev/null &
SCAN_PID=$!
sleep 15
kill $SCAN_PID 2>/dev/null
# Detailed BLE beacon analysis with btmon
sudo timeout 30 btmon | tee ble_capture.log | \
grep -Ei "ADV_IND|ADV_NONCONN|manufacturer|rssi|company"
# Filter for Apple Find My network beacons (AirTag signatures)
sudo hcitool lescan --duplicates 2>/dev/null | \
grep -i "4C:00" | sort -u # Apple company ID prefix
# --- Expected Output ---
# LE Scan ...
# 5A:3C:B8:19:44:F2 (unknown)
# 4C:00:AA:11:BE:C3 (unknown)
# 78:D1:62:0A:33:17 Tile Mate
# 4C:00:5F:22:91:DA (unknown)
# F0:C7:7F:88:AB:03 [TV] Samsung 65Q80
#
# --- btmon filtered output ---
# > HCI Event: LE Meta (0x3e) ADV_NONCONN_IND
# RSSI: -47 dBm Company: Apple, Inc. (76)
# Type: Find My (0x12) Payload: 07 19 01 48 2a...
# > HCI Event: LE Meta (0x3e) ADV_IND
# RSSI: -63 dBm Company: Tile, Inc. (272)
# > HCI Event: LE Meta (0x3e) ADV_NONCONN_IND
# RSSI: -51 dBm Company: Apple, Inc. (76)
# Type: Find My (0x12) Payload: 07 19 01 93 f1...#!/bin/bash
# Prerequisites: apt install bluez (provides hcitool, btmon)
# Platform: Linux only — macOS alternative: use nRF Connect app; Windows: use Bluetooth LE Explorer
# Comprehensive BLE tracker detection scan
# Detect AirTags, Tile, SmartTag, and unknown BLE beacons
# Quick scan for active BLE advertisers
sudo hcitool lescan --duplicates 2>/dev/null &
SCAN_PID=$!
sleep 15
kill $SCAN_PID 2>/dev/null
# Detailed BLE beacon analysis with btmon
sudo timeout 30 btmon | tee ble_capture.log | \
grep -Ei "ADV_IND|ADV_NONCONN|manufacturer|rssi|company"
# Filter for Apple Find My network beacons (AirTag signatures)
sudo hcitool lescan --duplicates 2>/dev/null | \
grep -i "4C:00" | sort -u # Apple company ID prefix
# --- Expected Output ---
# LE Scan ...
# 5A:3C:B8:19:44:F2 (unknown)
# 4C:00:AA:11:BE:C3 (unknown)
# 78:D1:62:0A:33:17 Tile Mate
# 4C:00:5F:22:91:DA (unknown)
# F0:C7:7F:88:AB:03 [TV] Samsung 65Q80
#
# --- btmon filtered output ---
# > HCI Event: LE Meta (0x3e) ADV_NONCONN_IND
# RSSI: -47 dBm Company: Apple, Inc. (76)
# Type: Find My (0x12) Payload: 07 19 01 48 2a...
# > HCI Event: LE Meta (0x3e) ADV_IND
# RSSI: -63 dBm Company: Tile, Inc. (272)
# > HCI Event: LE Meta (0x3e) ADV_NONCONN_IND
# RSSI: -51 dBm Company: Apple, Inc. (76)
# Type: Find My (0x12) Payload: 07 19 01 93 f1...Wi-Fi Probe Analysis
Capture and analyze Wi-Fi probe requests to understand your device's tracking surface.
#!/bin/bash
# Prerequisites: apt install aircrack-ng wireshark-common (provides tshark)
# Monitor Wi-Fi probe requests to understand device tracking surface
# Requires monitor-mode capable adapter
# Enable monitor mode
# ⚠ WARNING: 'check kill' stops NetworkManager — you WILL lose internet connectivity
sudo airmon-ng check kill
sudo airmon-ng start wlan0
# Capture probe requests with detailed fields
sudo tshark -i wlan0mon -f "subtype probe-req" -T fields \
-e frame.time -e wlan.sa -e wlan.sa_resolved \
-e wlan_mgt.ssid -e radiotap.dbm_antsignal \
-E header=y -E separator=, > probe_log.csv
# Analyze unique devices and their preferred networks
echo "=== Unique devices broadcasting ==="
cut -d',' -f2 probe_log.csv | sort | uniq -c | sort -rn | head -20
echo "=== Most broadcast SSIDs ==="
cut -d',' -f4 probe_log.csv | sort | uniq -c | sort -rn | head -20
# ⚠ Restore connectivity after capture:
# sudo airmon-ng stop wlan0mon && sudo systemctl restart NetworkManager
# Expected output:
# [Probe Requests Captured]
# MAC: aa:bb:cc:dd:ee:ff → SSID: "HomeNetwork-5G"
# MAC: aa:bb:cc:dd:ee:ff → SSID: "Starbucks_WiFi"
# MAC: 11:22:33:44:55:66 → SSID: "CorpNet-WPA3"
#
# ⚠ Exposure: 3 unique SSIDs from 2 devices — reveals home, work, and visited locations#!/bin/bash
# Prerequisites: apt install aircrack-ng wireshark-common (provides tshark)
# Monitor Wi-Fi probe requests to understand device tracking surface
# Requires monitor-mode capable adapter
# Enable monitor mode
# ⚠ WARNING: 'check kill' stops NetworkManager — you WILL lose internet connectivity
sudo airmon-ng check kill
sudo airmon-ng start wlan0
# Capture probe requests with detailed fields
sudo tshark -i wlan0mon -f "subtype probe-req" -T fields \
-e frame.time -e wlan.sa -e wlan.sa_resolved \
-e wlan_mgt.ssid -e radiotap.dbm_antsignal \
-E header=y -E separator=, > probe_log.csv
# Analyze unique devices and their preferred networks
echo "=== Unique devices broadcasting ==="
cut -d',' -f2 probe_log.csv | sort | uniq -c | sort -rn | head -20
echo "=== Most broadcast SSIDs ==="
cut -d',' -f4 probe_log.csv | sort | uniq -c | sort -rn | head -20
# ⚠ Restore connectivity after capture:
# sudo airmon-ng stop wlan0mon && sudo systemctl restart NetworkManager
# Expected output:
# [Probe Requests Captured]
# MAC: aa:bb:cc:dd:ee:ff → SSID: "HomeNetwork-5G"
# MAC: aa:bb:cc:dd:ee:ff → SSID: "Starbucks_WiFi"
# MAC: 11:22:33:44:55:66 → SSID: "CorpNet-WPA3"
#
# ⚠ Exposure: 3 unique SSIDs from 2 devices — reveals home, work, and visited locationsMAC Rotation Verification
Verify that your device's MAC address randomization is actually working by monitoring for static identifiers.
#!/usr/bin/env python3
# Prerequisites: subprocess is stdlib — no install needed
# Platform: Linux only (requires hcitool from bluez package)
"""Verify MAC address randomization is working on your devices.
Monitor BLE/Wi-Fi addresses over time to detect static identifiers."""
import subprocess
import time
import json
from collections import defaultdict
def scan_ble_addresses(duration=60, interval=10):
"""Scan for BLE addresses over time and flag non-rotating ones."""
seen = defaultdict(list)
scans = duration // interval
for i in range(scans):
# Note: subprocess timeout sends SIGTERM to cleanly stop the BLE scan after each interval
result = subprocess.run(
["sudo", "hcitool", "lescan", "--duplicates"],
capture_output=True, text=True, timeout=interval
)
timestamp = time.strftime("%H:%M:%S")
for line in result.stdout.strip().split("\n"):
parts = line.strip().split()
if len(parts) >= 2:
addr = parts[0]
seen[addr].append(timestamp)
time.sleep(1)
print(f"\n{'Address':<20} {'Times Seen':>10} {'Rotating':>10}")
print("-" * 42)
for addr, times in sorted(seen.items(), key=lambda x: -len(x[1])):
# If a MAC address appears in >50% of scan windows, it's likely using a static (non-rotating) address
rotating = "STATIC ⚠" if len(times) > scans * 0.5 else "OK ✓"
print(f"{addr:<20} {len(times):>10} {rotating:>10}")
scan_ble_addresses(duration=120, interval=15)#!/usr/bin/env python3
# Prerequisites: subprocess is stdlib — no install needed
# Platform: Linux only (requires hcitool from bluez package)
"""Verify MAC address randomization is working on your devices.
Monitor BLE/Wi-Fi addresses over time to detect static identifiers."""
import subprocess
import time
import json
from collections import defaultdict
def scan_ble_addresses(duration=60, interval=10):
"""Scan for BLE addresses over time and flag non-rotating ones."""
seen = defaultdict(list)
scans = duration // interval
for i in range(scans):
# Note: subprocess timeout sends SIGTERM to cleanly stop the BLE scan after each interval
result = subprocess.run(
["sudo", "hcitool", "lescan", "--duplicates"],
capture_output=True, text=True, timeout=interval
)
timestamp = time.strftime("%H:%M:%S")
for line in result.stdout.strip().split("\n"):
parts = line.strip().split()
if len(parts) >= 2:
addr = parts[0]
seen[addr].append(timestamp)
time.sleep(1)
print(f"\n{'Address':<20} {'Times Seen':>10} {'Rotating':>10}")
print("-" * 42)
for addr, times in sorted(seen.items(), key=lambda x: -len(x[1])):
# If a MAC address appears in >50% of scan windows, it's likely using a static (non-rotating) address
rotating = "STATIC ⚠" if len(times) > scans * 0.5 else "OK ✓"
print(f"{addr:<20} {len(times):>10} {rotating:>10}")
scan_ble_addresses(duration=120, interval=15)Device Tracking Surface Audit
Comprehensive audit of your device's tracking exposure across all vectors.
#!/bin/bash
# Platform: Linux only (uses ip, nmcli, hciconfig, systemctl)
# Prerequisites: apt install bluez network-manager
# Comprehensive device tracking surface audit
echo "=== Active Network Interfaces ==="
ip link show | grep -E "^[0-9]|link/ether"
echo -e "\n=== Wi-Fi Connection History (reveals preferred networks) ==="
# Linux (NetworkManager)
nmcli connection show | head -20
# macOS equivalent:
# defaults read /Library/Preferences/SystemConfiguration/com.apple.airport.preferences | grep SSIDString
echo -e "\n=== Current DNS Leaks ==="
dig +short myip.opendns.com @resolver1.opendns.com
echo -e "\n=== Active Location Services ==="
# Check if location services are active (Linux)
systemctl status geoclue 2>/dev/null || echo "geoclue not found"
echo -e "\n=== Bluetooth Status ==="
hciconfig -a 2>/dev/null | grep -E "Name|Address|Status"
bluetoothctl show 2>/dev/null | grep -E "Name|Address|Powered|Discoverable"
echo -e "\n=== Advertising ID Status (Android via ADB) ==="
# adb shell settings get secure advertising_id 2>/dev/null
echo "Use: Settings > Privacy > Ads > Delete advertising ID"
# Expected output:
# === Device Tracking Surface Audit ===
# [Wi-Fi]
# Interface: wlan0 | MAC: aa:bb:cc:dd:ee:ff
# MAC Randomization: ENABLED ✓
# Connected SSID: HomeNetwork-5G
# Saved Networks: 12 (⚠ each stored SSID is a tracking vector)
#
# [Bluetooth]
# Interface: hci0 | Address: 11:22:33:44:55:66
# Status: UP RUNNING
# Discoverable: NO ✓
#
# [Location Services]
# GPS: disabled ✓#!/bin/bash
# Platform: Linux only (uses ip, nmcli, hciconfig, systemctl)
# Prerequisites: apt install bluez network-manager
# Comprehensive device tracking surface audit
echo "=== Active Network Interfaces ==="
ip link show | grep -E "^[0-9]|link/ether"
echo -e "\n=== Wi-Fi Connection History (reveals preferred networks) ==="
# Linux (NetworkManager)
nmcli connection show | head -20
# macOS equivalent:
# defaults read /Library/Preferences/SystemConfiguration/com.apple.airport.preferences | grep SSIDString
echo -e "\n=== Current DNS Leaks ==="
dig +short myip.opendns.com @resolver1.opendns.com
echo -e "\n=== Active Location Services ==="
# Check if location services are active (Linux)
systemctl status geoclue 2>/dev/null || echo "geoclue not found"
echo -e "\n=== Bluetooth Status ==="
hciconfig -a 2>/dev/null | grep -E "Name|Address|Status"
bluetoothctl show 2>/dev/null | grep -E "Name|Address|Powered|Discoverable"
echo -e "\n=== Advertising ID Status (Android via ADB) ==="
# adb shell settings get secure advertising_id 2>/dev/null
echo "Use: Settings > Privacy > Ads > Delete advertising ID"
# Expected output:
# === Device Tracking Surface Audit ===
# [Wi-Fi]
# Interface: wlan0 | MAC: aa:bb:cc:dd:ee:ff
# MAC Randomization: ENABLED ✓
# Connected SSID: HomeNetwork-5G
# Saved Networks: 12 (⚠ each stored SSID is a tracking vector)
#
# [Bluetooth]
# Interface: hci0 | Address: 11:22:33:44:55:66
# Status: UP RUNNING
# Discoverable: NO ✓
#
# [Location Services]
# GPS: disabled ✓Detection First
Faraday Bag Testing Protocol
A Faraday bag is only as good as its attenuation. "No bars" on a phone display is not a reliable test — cellular baseband can still transmit at reduced power. Use this protocol to validate shielding effectiveness.
Validation Steps
- 1. Use an RF signal meter — place a transmitting device inside the bag and measure signal leakage with a calibrated RF meter (e.g., RF Explorer, TinySA Ultra) across cellular (700-2600 MHz), Wi-Fi (2.4/5 GHz), BLE (2.4 GHz), and GPS (1575 MHz) bands. Do not rely on the phone's signal bar display.
- 2. Verify >80 dB attenuation across all target bands. Measure baseline signal outside the bag, then inside. The difference should exceed 80 dB for cellular, Wi-Fi, BLE, and GPS. Bags that attenuate cellular but leak BLE provide a false sense of security.
- 3. Test after repeated use — zipper and seal mechanisms degrade over time. Re-test attenuation after 50+ open/close cycles, after exposure to moisture, and after extended folding. Velcro and roll-top closures tend to degrade faster than RF-gasketed zippers.
- 4. Reputable brands: Mission Darkness and Silent Pocket are commonly referenced in the security community. These are not endorsements — always verify attenuation independently with your own testing equipment before relying on any bag for operational security.
iOS vs Android Privacy Comparison
Both platforms offer privacy features, but with different philosophies. iOS prioritizes built-in controls with limited user customization; Android offers deeper system access at the cost of complexity.
| Feature | iOS | Android |
|---|---|---|
| Hardening mode | Lockdown Mode — disables JIT, link previews, shared albums, MDM profiles | Custom ROMs: GrapheneOS (hardened AOSP), CalyxOS (usability-focused privacy ROM) |
| Tracking protection | App Tracking Transparency (ATT) — per-app opt-in for cross-app tracking | Delete advertising ID (Android 12+), per-app permission controls |
| Email privacy | Mail Privacy Protection — blocks tracking pixels, hides IP from senders | No built-in equivalent — requires third-party email clients |
| BLE scanning | Limited BLE scanning tools due to App Store restrictions | Full BLE scanner access — nRF Connect, BLE Scanner, custom apps |
| Tracker alerts | Built-in AirTag safety alerts, Find My network detection | AirGuard app, Google Find My Device tracker alerts (Android 14+) |
| Network privacy | iCloud Private Relay — dual-hop proxy for Safari and DNS | Full VPN/proxy configuration, DNS-over-HTTPS system-wide |
| Radio-level tools | No access — baseband and radio stack are completely locked | Full root access for radio tools, SnoopSnitch (IMSI catcher detection), carrier unlock flexibility |
Geofence & Keyword Warrants
Why Location Data Matters
The landmark Carpenter v. United States (2018) Supreme Court ruling established that accessing historical cell-site location records constitutes a search under the Fourth Amendment, requiring a warrant. However, geofence warrants operate differently — they identify unknown suspects rather than surveilling a known target — and their legal status remains actively contested across federal circuits.
Practical implications: Any device with location services enabled and linked to a Google, Apple, or carrier account can potentially appear in geofence warrant results. Disabling location history, using non-logged DNS, minimizing account-linked location services, and compartmentalizing devices reduce exposure to these dragnet-style requests.
Related: Data Privacy Controls
Defense Strategy Summary
- Minimize radio emissions: disable unused radios, enable MAC randomization, remove saved networks
- Control app telemetry: revoke background location, disable ad IDs, block analytics SDKs via DNS
- Detect trackers: run periodic BLE scans, enable stalker-device alerts, audit vehicles and belongings
- Harden cellular: disable 2G fallback, use encrypted DNS, compartmentalize SIM identities
- Monitor continuously: audit weekly, re-check after updates, log unexpected network connections
Device Tracking Labs
Hands-on exercises to discover and reduce your device tracking surface.