Apple changed their documentation at my request but it proves they don't care about privacy

Sep 03, 2026 Last reply: 2 weeks ago 104 Replies

After having read the prior responses in this Jon/Carlos tangent...

I apologize if I haven't explained the situation to the liking of people who haven't clicked on the references, but I am happy that Jon and Carlos (and Andy and Lawrence, all of whom I respect) are trying to understand.

I especially wish to thank Jon Ribbens and Carlos & any others who have bothered to read the links provided, because they explain the issue well.

If people haven't read the references, then they're stuck in the stone age of understanding, which, well, which I'm not the one to drag them out of.

I just don't have the skills to explain that an SSID is not a BSSID (as witnessed by those who claimed changing the SSID changes the BSSID).

These are basic networking concepts.

Regarding locations, I don't have the skills to explain what a set of GPS coordinates means, if people claim it's "just a map". I don't even know _how_ to _begin_ to explain that your home address is NOT "just a map".

I don't even know how to explain to people who claim that the router never travels as their belief system is so absurd as to warn me that if they don't understand that people take their routers with them when they move, then that kind of person will never be able to understand, well, anything.

I apologize that I don't have the skills set to bring folks out of the stone age, when they claim a home address is "just a location on a map".

People who make those claims will never be able to comprehend why it is so trivial for Jon & me to surveil their movements using the Apple WPS db.

In summary, if people haven't read this paper, I don't have the skill set to explain the very simple concepts which are described in that paper. *Surveilling the Masses with Wi-Fi-Based Positioning Systems*

formatting link

The paper is about surveillance of masses (not individuals, per se), knowing every single location of billions of router BSSIDs around the world, from anywhere in the world, by anyone in the world, with zero restrictions, which is only possible using Apple's WPS database (not Google's, which has huge restrictions on both the input and output).

Apple has zero restrictions on the input. And a restriction of the nearest 400 BSSIDs/GPS pairs on the output.

But... that restriction is meaningless, as I wrote and ran the Python code on Windows that took the furthest away of those 400 to run it again.

And again. And again. And again. I stopped at something like thousands. So now I have the nearest ten thousand BSSIDs starting at my home.

Notice I have the GPS location of each of those unique ten thousand BSSIDs.

And, since apartments basically do not exist in this suburban area, I actually know the names and address of the owners of record of those homes.

If any of those ten thousand people ever move, and take their router with them, I will instantly know exactly where they moved to, within seconds.

Not only that, but I will instantly know the nearest 400 BSSIds, so if they moved, oh, say, into someone else's home, I'll know exactly who that is.

To be very clear, this is only possible because of how Apple designed it. Google and Mozilla designed their systems completely differently.

Only Apple's design is this bad in terms of privacy.

As for the hidden-BSSID issue, I was unaware of that until I found, to my horror, my own hidden BSSIDs in Apple's WPS database. That was a shock!

At the time, I looked up Apple's public policy, and it was silent on the issue of what Apple does when it encounters a hidden-broadcast BSSID.

When I brought it up to my next-door neighbor, who runs Apple Maps, he said he'd check it out, which, after a few weeks of emails back and forth, we found out that Apple has no intention of honoring the intent of a hidden broadcast (even as we know Google & Mozilla certainly honor that intent).

The Apple lawyers made that very clear to me, as I was shut out from talking to the engineers once the lawyers were informed of the issue.

I had given up, but recently, I happened to look at Apple's documentation, and I realized Apple proved they had no intent of honoring the long-held intention of a hidden broadcast, by simply changing their documentation.

formatting link

Clearly, I know what I'm talking about, so my well informed assessment, based on those verifiable facts, is Apple doesn't care about our privacy.

On Usenet we can have intelligent discussions with well-meaning people.

Hi Keith Thompson,

Thank you for bringing up your point of view, as all points are valid here. This is Usenet where we welcome deep detailed discussion of tech topics.

Jon Ribbens clearly ran the code so we have proof that it was referenced properly enough for him to have run it on his machine to prove the point.

Nonetheless, it's good you're *asking* for the Python code, which I only ran on Windows 10, and which I'm happy to supply to you for all to review.

Please keep in mind the progression of this topic started with this paper: *Surveilling the Masses with Wi-Fi-Based Positioning Systems*

formatting link

As Jon Ribbens did, I simply ran the Python code in that article on my PC.

Since all the dozens of access points on my property have always had both a hidden broadcast & a _nomap prefix, I was horrified to see them on the map!

At that time, we discussed this issue at length, where the following code resulted which I will provide to the team to try themselves on their PC.

12/17/2025 02:28 PM 2,934 bssid.bat.txt 12/17/2025 02:28 PM 4,309 bssidcheck.bat.txt 12/17/2025 02:28 PM 1,979 bssidcompare.bat.txt 12/17/2025 02:28 PM 316 bssidgenerate.bat.txt 12/17/2025 02:28 PM 4,312 bssidgenerate.ps1.txt 12/17/2025 02:28 PM 1,348 bssidplot.py.txt 12/17/2025 02:28 PM 27,527 bssid_results.txt

Let's start with the first on that list, and proceed from there, so that anyone with this code can track every single router location in the world.

Here is bssid.bat

@echo off setlocal EnableDelayedExpansion :: C:\app\os\python\apple_bssid_locator\bssid.bat :: Use: bssid.bat <Enter> (then enter desired BSSID to look up) :: Sample values: :: 00:18:f8:c1:4a:65 :: 00:07:89:d7:82:e8 :: 04:09:A5:3B:34:67 :: :: Logs up to 400 BSSID:GPS pairs from Apple's WPS public database :: Loop until user types q :: :: Changelog: :: v1p0 20251205 - Query Apple's highly insecure WPS database :: v1p1 20251214 - Saves to time-date stamped results.txt log file :: v1p2 20251215 - Timestamp results.txt so it's not overwritten :: v1p3 20251219 - Limit the human-readable GPS to 6 decimal places :: v1p4 20251219 - Show original raw integers + converted decimals :: v1p5 20251219 - Tried to accomodate Google Maps query to new format :: v1p6 20251219 - Changed to block-aware parsing with debug output :: v1p7 20251219 - Enable delayed expansion to fix parsing inside loops set LOGDIR=%~dp0log if not exist "%LOGDIR%" mkdir "%LOGDIR%" :: Create a unique session log (YYYYMMDD_HHMMSS) for /f %%A in ('wmic os get localdatetime ^| find "."') do set dt0=%%A set "session_ts=%dt0:~0,8%_%dt0:~8,6%" set "session_log=%LOGDIR%\session_%session_ts%.log" echo === New BSSID lookup session started at %date% %time% === >>

"%session_log%" echo. echo === Nearby Wi-Fi Networks === netsh wlan show networks mode=bssid echo ============================= :loop echo. set /p BSSID=Enter the BSSID (or q to quit): if /I "%BSSID%"=="q" goto end :: --- Clean up input --- set "BSSID=%BSSID:"=%" set "BSSID=%BSSID: =%" :: --- Make filename-safe version --- set "safeBSSID=%BSSID::=-%" :: --- Generate timestamp for THIS lookup --- for /f %%A in ('wmic os get localdatetime ^| find "."') do set dt=%%A set "ts=%dt:~0,8%_%dt:~8,6%" :: --- Timestamped output file --- set "outfile=%LOGDIR%\bssid_%safeBSSID%_%ts%.txt" :: --- Clear previous coordinates --- set "LAT=" set "LON=" echo === Lookup started at %date% %time% === > "%outfile%" echo BSSID: %BSSID% >> "%outfile%" echo. >> "%outfile%" :: --- Run Python lookup --- python.exe apple_bssid_locator.py %BSSID% --all >> "%outfile%" :: --- Display results --- echo ----------------------------------------------- type "%outfile%" echo ----------------------------------------------- :: --- Block-aware parsing of coordinates (with delayed expansion) --- set "CAPTURE=" set "LAT=" set "LON=" for /f "usebackq delims=" %%L in ("%outfile%") do ( if /i "%%L"=="BSSID: %BSSID%" ( set "CAPTURE=1" set "LAT=" set "LON=" echo [DEBUG] Found block start for %BSSID% ) else if defined CAPTURE ( echo [DEBUG] Line in block: %%L echo %%L | findstr /i /c:"Latitude (degrees):" >nul if not errorlevel 1 ( for /f "tokens=2 delims=:" %%A in ("%%L") do set "LAT=%%A" if defined LAT set "LAT=!LAT: =!" echo [DEBUG] Parsed LAT candidate = "!LAT!" ) echo %%L | findstr /i /c:"Longitude (degrees):" >nul if not errorlevel 1 ( for /f "tokens=2 delims=:" %%B in ("%%L") do set "LON=%%B" if defined LON set "LON=!LON: =!" echo [DEBUG] Parsed LON candidate = "!LON!" ) if defined LAT if defined LON ( goto :gotCoords ) echo %%L | findstr /i /c:"BSSID:" >nul if not errorlevel 1 ( set "CAPTURE=" ) ) ) :gotCoords echo [DEBUG] Final LAT = "!LAT!" echo [DEBUG] Final LON = "!LON!" :: --- Validate parsed coordinates --- if not defined LAT echo [DEBUG][ERROR] Latitude not captured. Check Python output format near "BSSID: %BSSID%". if not defined LON echo [DEBUG][ERROR] Longitude not captured. Check Python output format near "BSSID: %BSSID%". :: --- Save results --- echo === Lookup finished at %date% %time% === >> "%outfile%" echo. >> "%outfile%" :: --- Append to session log --- echo [%date% %time%] BSSID: %BSSID% >> "%session_log%" echo Latitude: !LAT! >> "%session_log%" echo Longitude: !LON! >> "%session_log%" echo. >> "%session_log%" :: --- Append to master log --- echo [%date% %time%] BSSID: %BSSID% >> "%LOGDIR%\results.log" echo Latitude: !LAT! >> "%LOGDIR%\results.log" echo Longitude: !LON! >> "%LOGDIR%\results.log" echo. >> "%LOGDIR%\results.log" :: --- Open in Google Maps --- if defined LAT if defined LON start msedge "

formatting link
!" goto loop :end echo Exiting. Goodbye! endlocal :: end of C:\app\os\python\apple_bssid_locator\bssid.bat

bssid.bat

bssidcheck.bat

@echo off :: This is C:\app\os\python\apple_bssid_locator\bssidcheck.bat :: v1p0 20251217 :: reads a list of made-up BSSIDs from bssidcheck.txt :: outputs to the console and into a timestamped log file :: v1p1 20251217 :: added fullpath to output files in the console output :: v1p2 20251217 :: only log when a lookup is successful :: v1p3 20251217 :: added summary section of bssid's that were found :: Begin Log setup set LOGDIR=%~dp0log if not exist "%LOGDIR%" mkdir "%LOGDIR%" for /f %%A in ('wmic os get localdatetime ^| find "."') do set dt0=%%A set "session_ts=%dt0:~0,8%_%dt0:~8,6%" set "session_log=%LOGDIR%\session_%session_ts%.log" :: End Log setup :: --- begin Success list setup --- set "FOUND_LIST=" :: --- end Success list setup --- echo === New BSSID lookup session started at %date% %time% === >> "%session_log%" echo Session log: %session_log% :: Begin FILE MODE if exist "%~dp0bssidcheck.txt" ( echo Processing BSSIDs from bssidcheck.txt... for /f "usebackq tokens=*" %%X in ("%~dp0bssidcheck.txt") do ( set "BSSID=%%X" call :process_bssid ) goto end ) :: End FILE MODE :: Begin INTERACTIVE MODE :loop echo. set /p BSSID=Enter the BSSID (or q to quit): if /I "%BSSID%"=="q" goto end call :process_bssid goto loop :: End INTERACTIVE MODE :: Begin PROCESS ONE BSSID :process_bssid :: --- Clean up input --- set "BSSID=%BSSID:"=%" set "BSSID=%BSSID: =%" :: --- begin Make filename-safe version --- set "safeBSSID=%BSSID::=-%" :: --- end Make filename-safe version --- :: --- begin Generate timestamp for THIS lookup --- for /f %%A in ('wmic os get localdatetime ^| find "."') do set dt=%%A set "ts=%dt:~0,8%_%dt:~8,6%" :: --- end Generate timestamp for THIS lookup --- :: --- begin Timestamped output file --- set "outfile=%LOGDIR%\bssidlookup_%ts%_%safeBSSID%.log" :: --- end Timestamped output file --- :: --- begin Clear previous coordinates --- set LAT= set LON= :: --- end Clear previous coordinates --- :: --- begin Run Python lookup --- echo === Lookup started at %date% %time% === > "%outfile%" echo BSSID: %BSSID% >> "%outfile%" echo. >> "%outfile%" python.exe apple_bssid_locator.py %BSSID% --all >> "%outfile%" :: --- end Run Python lookup --- :: --- begin Display results --- echo ----------------------------------------------- type "%outfile%" echo ----------------------------------------------- if defined LAT if defined LON echo Log written to: %outfile% :: --- end Display results --- :: --- begin Extract coordinates --- for /f "tokens=2 delims=: " %%A in ('findstr /i "Latitude" "%outfile%"') do set LAT=%%A for /f "tokens=2 delims=: " %%B in ('findstr /i "Longitude" "%outfile%"') do set LON=%%B echo === Lookup finished at %date% %time% === >> "%outfile%" echo. >> "%outfile%" :: --- end Extract coordinates --- :: --- begin Append to session log --- if defined LAT if defined LON ( echo [%date% %time%] BSSID: %BSSID% >> "%session_log%" echo Latitude: %LAT% >> "%session_log%" echo Longitude: %LON% >> "%session_log%" echo. >> "%session_log%" :: Add to success list set "FOUND_LIST=%FOUND_LIST% %BSSID%" ) :: --- end Append to session log --- :: --- begin Append to master log --- if defined LAT if defined LON ( echo [%date% %time%] BSSID: %BSSID% >> "%LOGDIR%\bssidcheck_%session_ts%.log" echo Latitude: %LAT% >> "%LOGDIR%\bssidcheck_%session_ts%.log" echo Longitude: %LON% >> "%LOGDIR%\bssidcheck_%session_ts%.log" echo. >> "%LOGDIR%\bssidcheck_%session_ts%.log" ) :: --- end Append to master log --- :: --- begin Open in Google Maps --- if defined LAT if defined LON start msedge "

formatting link
" :: --- end Open in Google Maps --- goto :eof :: End PROCESS ONE BSSID :end :: --- begin Summary of successful lookups --- echo. echo ===== Summary of Successful BSSID Lookups ===== if defined FOUND_LIST ( echo %FOUND_LIST% ) else ( echo No BSSIDs were successfully located. ) echo =============================================== echo. :: --- end Summary of successful lookups --- echo Exiting. Goodbye! :: end of C:\app\os\python\apple_bssid_locator\bssidcheck.bat

bssidcheck.bat

bssidcompare.bat

@echo off :: This is C:\app\os\python\apple_bssid_locator\bssidcompare.bat :: v1p0 20251215 :: Outputs if there is movecment for any given BSSID in results.txt setlocal enabledelayedexpansion :: Threshold for movement (where 0.001 degrees is roughly 100 kilometers) set THRESH=0.001 :: Input file collected using apple_bssid_locator open source code :: These are actual BSSID:GPS pairs which you can test yourself! :: 28:6d:97:c8:5a:30 35.2948265 126.77577972 :: 00:22:3f:a5:7b:33 35.29422378 126.77641296 :: 10:62:e5:b1:8f:12 35.29444885 126.77671051 :: 12:09:a5:53:df:13 35.29491043 126.77599334 :: 28:6d:97:4f:be:d0 35.29439163 126.77655029 :: 28:6d:97:b9:89:96 35.29463195 126.77554321000001 :: 42:09:a5:53:df:13 35.294940940000004 126.7760086 set INFILE=results.txt echo Checking for GPS movement greater than %THRESH% degrees... echo. :: Loop through each line of results.txt for /f "tokens=1,2,3 delims= " %%A in (%INFILE%) do ( set BSSID=%%A set LAT=%%B set LON=%%C :: If we've seen this BSSID before, compare if defined lastLAT[!BSSID!] ( set /a diffLAT=1000000*( !LAT! - !lastLAT[!BSSID!]! ) set /a diffLON=1000000*( !LON! - !lastLON[!BSSID!]! ) :: Convert to absolute values if !diffLAT! lss 0 set /a diffLAT=-!diffLAT! if !diffLON! lss 0 set /a diffLON=-!diffLON! :: Compare against threshold (scaled by 1,000,000) set /a threshScaled=%THRESH%*1000000 if !diffLAT! gtr !threshScaled! ( echo BSSID !BSSID! moved in LAT by more than %THRESH% degrees ) if !diffLON! gtr !threshScaled! ( echo BSSID !BSSID! moved in LON by more than %THRESH% degrees ) ) :: Store current coordinates set lastLAT[!BSSID!]=!LAT! set lastLON[!BSSID!]=!LON! ) echo. echo Comparison complete. endlocal :: end of C:\app\os\python\apple_bssid_locator\bssidcompare.bat

bssidcompare.bat

bssidgenerate.bat

@echo off :: C:\app\os\python\apple_bssid_locator\bssidgenerate.bat :: Runs bssidgenerate.ps1 to generate random/sequential realistic BSSIDs set "SCRIPT=%~dp0bssidgenerate.ps1" echo Running PowerShell script: echo %SCRIPT% echo. powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT%"

bssidgenerate.bat

bssidgenerate.ps1

# C:\app\os\python\apple_bssid_locator\bssidgenerate.ps1 # Usemodel: bssidgenerate.bat (runs this powershell script) # v1p0 20251217 # Generates BSSIDs based on user input. # Prompts for: # 1. OUI (first half), e.g., F4:F2:6D (TP-Link) # 2. Number of BSSIDs to generate (e.g., 100) # 3. Mode: R = random, S = sequential # v1p1 20251217 # Saves results to bssidinput.txt # Forces an OUI in case enter is hit prematurely # v1p2 20251217 # Added menu of the ten most common USA OUI's # v1p3 20251217 # Added sequential-mode starting block # v1p4 20251217 # Added wraparound protection (at FF:FF:FF) # --- BEGIN OUI MENU BLOCK --- Write-Host "" Write-Host "Select an OUI from the menu or press Enter to type your own:" Write-Host " 1) TP-Link F4:F2:6D" Write-Host " 2) Netgear 44:94:FC" Write-Host " 3) Arris 60:31:97" Write-Host " 4) Ubiquiti 24:A4:3C" Write-Host " 5) Technicolor 10:13:31" Write-Host " 6) Cisco/Linksys 00:25:9C" Write-Host " 7) ASUS AC:9E:17" Write-Host " 8) Google/Nest F4:F5:D8" Write-Host " 9) Amazon/Eero 74:83:C2" Write-Host " 10) Hitron C8:3A:35" Write-Host "" $choice = Read-Host "Enter menu number (1-10) or press Enter to type your own" switch ($choice) { "1" { $oui = "F4:F2:6D" } "2" { $oui = "44:94:FC" } "3" { $oui = "60:31:97" } "4" { $oui = "24:A4:3C" } "5" { $oui = "10:13:31" } "6" { $oui = "00:25:9C" } "7" { $oui = "AC:9E:17" } "8" { $oui = "F4:F5:D8" } "9" { $oui = "74:83:C2" } "10" { $oui = "C8:3A:35" } default { $oui = $null } } # --- END OUI MENU BLOCK --- # Ask for the first half (OUI) if (-not $oui) { $oui = Read-Host "Enter the first half (e.g., F4:F2:6D)" } $oui = $oui.ToUpper().Replace("-",":").Trim() # Prevent empty OUI if (-not $oui) { Write-Host "You must enter an OUI such as F4:F2:6D." exit } # Ask how many BSSIDs to generate $count = Read-Host "How many BSSIDs do you want to generate?" $count = [int]$count # Ask for mode: random or sequential $mode = Read-Host "Random or Sequential? (R/S)" $mode = $mode.ToUpper() Write-Host "" Write-Host "Generating BSSIDs..." Write-Host "" # Output file $outfile = "bssidinput.txt" Clear-Content -Path $outfile -ErrorAction SilentlyContinue # Function to format a number 0¡V255 as two hex digits function To-Hex([int]$n) { return "{0:X2}" -f $n } # Sequential mode if ($mode -eq "S") { # Ask for starting second-half (e.g., AB:CD:EF) $startHex = Read-Host "Enter starting second-half (e.g., AB:CD:EF) or press Enter for 00:00:00" if (-not $startHex) { $startHex = "00:00:00" } # Normalize $startHex = $startHex.ToUpper().Replace("-",":").Trim() # Convert to integer $parts = $startHex.Split(":") if ($parts.Count -ne 3) { Write-Host "Invalid starting value. Must be three bytes like AB:CD:EF." exit } $startVal = ([Convert]::ToInt32($parts[0],16) -shl 16) `

  • ([Convert]::ToInt32($parts[1],16) -shl 8) `
  • [Convert]::ToInt32($parts[2],16) $maxVal = 0xFFFFFF for ($i = 0; $i -lt $count; $i++) { $val = $startVal + $i if ($val -gt $maxVal) { Write-Host "Reached maximum value FF:FF:FF. Stopping." break } $b1 = ($val -shr 16) -band 0xFF $b2 = ($val -shr 8) -band 0xFF $b3 = $val -band 0xFF $bssid = "${oui}:{0}:{1}:{2}" -f (To-Hex $b1), (To-Hex $b2), (To-Hex $b3) Write-Host $bssid Add-Content -Path $outfile -Value $bssid } } # Random mode elseif ($mode -eq "R") { $rand = New-Object System.Random for ($i = 0; $i -lt $count; $i++) { $b1 = $rand.Next(0,256) $b2 = $rand.Next(0,256) $b3 = $rand.Next(0,256) $bssid = "${oui}:{0}:{1}:{2}" -f (To-Hex $b1), (To-Hex $b2), (To-Hex $b3) Write-Host $bssid Add-Content -Path $outfile -Value $bssid } } else { Write-Host "Invalid choice. Please enter R or S." } Write-Host "" Write-Host "Output file saved to: $(Resolve-Path $outfile)" # end of C:\app\os\python\apple_bssid_locator\bssidgenerate.ps1
bssidgenerate.ps1

bssidplot.py

import folium # This is C:\app\os\python\bssidplot.py # USAGE: python bssidplot.py # v1p0 20251214 # Plots en masse GPS:BSSID pairs from results.txt using FOSS Folium # v1p1 20251215 # Generates bssid_map.html from results.txt using Folium # v1p2 20251215 # Brings up the bssid_map.html plot using the default web browser import folium # Read results.txt points = [] with open("results.txt") as f: for line in f: parts = line.strip().split("\t") if len(parts) == 3: mac, lat, lon = parts points.append((mac, float(lat), float(lon))) if not points: print("No points found in results.txt") exit() # Center map on the first point start_lat, start_lon = points[0][1], points[0][2] m = folium.Map(location=[start_lat, start_lon], zoom_start=15) # Add markers for mac, lat, lon in points: folium.Marker( location=[lat, lon], popup=f"{mac}\n({lat}, {lon})", icon=folium.Icon(color="blue", icon="wifi", prefix="fa") ).add_to(m) # Save map m.save("bssid_map.html") print("Map saved to bssid_map.html") # Open map in Microsoft Edge import subprocess import os map_path = os.path.abspath("bssid_map.html") import subprocess subprocess.Popen(['cmd', '/c', 'start', '', map_path]) # end of C:\app\os\python\bssidplot.py

bssidplot.py

Hi Jon Ribbens,

You are intelligent, and I've been a bit brutal to those who have been idiotically trolling this newsgroup without even reading the subject line, so I want to first thank you for actually reading the paper & testing it.

*Surveilling the Masses with Wi-Fi-Based Positioning Systems*
formatting link

You are at the stage where you ran the apple_bssid_locator.py script and you found that your own BSSID/GPS pair was clearly in the results.

I had run the same code as you just did, where I was horrified a dozen of mine were in the results since _all_ of them had _nomap on the SSID!

Luckily, I live near to plenty of Silicon Valley executives, where my next-door neighbor happens to an executive in the Apple Maps group.

When I brought the topic up to him, he at first considered it a likely bug, and then his engineers tried to snow me by saying the issue wasn't reproducible, but I kept hammering him on an honest answer.

In the end, he said I could only talk to the lawyers, who, in the end, said they'd "fix" the documentation, which, let's be clear, is the topic.

Apple did fix the documentation. Apple has no intention of honoring what EVERY other company already honors!

Subsequently, I had discussions with Daniel Veditz and Brian Krebs, and they agreed with the tests, so at this point, there isn't much we can do.

At this point, you seem to be the only one who displays any indication that they understood the topic of this paper & what it means for privacy (given you ran the python code and it clearly told you where you lived).

I appreciate that you followed up by running the apple_bssid_locator.py script, where I went another step further to modify that script so that it not only reports a single output, but the next nearest 400 BSSIDs.

With the code below and the code I posted in response to Keith Roberts who claimed, apparently, that you hadn't run the code you did run, you can literally track any router BSSID location anywhere in the world.

Forever...

Here is the improved apple_bssid_locator.py for you to test, where I simply ask of you to run it, and for you to explain to the newsgroups what it does, as people seem to be saying I can't explain things well.

Maybe you can do better than I at explaining what this code does?

#!/usr/bin/env -S uv run --script # -*- coding: utf-8 -*- # C:\app\os\python\apple_bssid_locator\apple_bssid_locator.py # Queries Apple WPS database for GPS:BSSID location pairs # Implementation based on

formatting link
# # Usage: apple_bssid_locator.py 11:22:33:AA:BB:CC # Usage: apple_bssid_locator.py 11:22:33:AA:BB:CC --all # Usage: apple_bssid_locator.py 11:22:33:AA:BB:CC --map # # Changelog: # v1p0 20251205 - Initial version from apple_bssid_locator.py # v1p1 20251214 - Added logging to results.txt # v1p2 20251215 - Timestamped results.txt to avoid overwrites # v1p3 20251219 - Limited output to 6 decimal places # v1p4 20251219 - Added raw integer output alongside converted decimals # v1p5 20251222 - Fixed raw to decimal conversion (divide by 100 Million) import argparse import requests import webbrowser import AppleWLoc_pb2 def parse_arguments(): parser = argparse.ArgumentParser() parser.add_argument("bssid", type=str, help="display the location of the bssid") parser.add_argument("-m", "--map", help="shows the location on google maps", action='store_true') parser.add_argument("-a", "--all", help="shows all results returned, not just the requested one", action='store_true') args = parser.parse_args() return args def format_bssid(bssid): return ':'.join(e.rjust(2, '0') for e in bssid.split(':')) def query_bssid(bssid, output_file="results.txt"): apple_wloc = AppleWLoc_pb2.AppleWLoc() wifi_device = apple_wloc.wifi_devices.add() wifi_device.bssid = bssid apple_wloc.unknown_value1 = 0 apple_wloc.return_single_result = 0 # request ALL results serialized_apple_wloc = apple_wloc.SerializeToString() length_serialized_apple_wloc = len(serialized_apple_wloc) headers = {'User-Agent':'locationd/1753.17 CFNetwork/889.9 Darwin/17.2.0'} data = b"\x00\x01\x00\x05"+b"en_US"+b"\x00\x13"+b"com.apple.locationd"+b"\x00\x0a"+b"8.1.12B411"+b"\x00\x00\x00\x01\x00\x00\x00" + bytes((length_serialized_apple_wloc,)) + serialized_apple_wloc r = requests.post('
formatting link
', headers=headers, data=data) apple_wloc = AppleWLoc_pb2.AppleWLoc() apple_wloc.ParseFromString(r.content[10:]) # Build dictionary of results results = {} with open(output_file, "w") as f: for wifi_device in apple_wloc.wifi_devices: if wifi_device.HasField('location'): raw_lat = wifi_device.location.latitude raw_lon = wifi_device.location.longitude lat = raw_lat * 1e-8 lon = raw_lon * 1e-8 mac = format_bssid(wifi_device.bssid) results[mac] = (lat, lon, raw_lat, raw_lon) # Write both raw integers and converted decimals (8 decimal places) f.write(f"{mac}\t{raw_lat}\t{raw_lon}\t{lat:.8f}\t{lon:.8f}\n") print(f"Saved {len(results)} entries to {output_file}") return results def main(): args = parse_arguments() print("Searching for location of bssid: %s" % args.bssid) results = query_bssid(args.bssid) # Determine which BSSIDs to process bssids_to_process = results.keys() if args.all else [args.bssid.lower()] found = False for bssid in bssids_to_process: if bssid in results: lat, lon, raw_lat, raw_lon = results[bssid] if lat == -180.0 and lon == -180.0: continue # Skip entries that were not found if found: print() print(f"BSSID: {bssid}") print(f"Raw latitude integer: {raw_lat}") print(f"Raw longitude integer: {raw_lon}") print(f"Latitude (degrees): {lat:.8f}") print(f"Longitude (degrees): {lon:.8f}") if args.map: url = f"
formatting link
{lat:.8f},{lon:.8f}" webbrowser.open(url) found = True if not found: print("The bssid was not found.") if __name__ == '__main__': main() # end of C:\app\os\python\apple_bssid_locator\apple_bssid_locator.py

With the code supplied above, anyone can easily track the movements of every access point BSSID in the world (that is in Apple's WPS database). *Surveilling the Masses with Wi-Fi-Based Positioning Systems*

formatting link

Note the word "mass" indicates we can not only track a single BSSID's location, but we can track every single BSSID in the world's location.

It's trivial to do, but only with Apple's WPS database. It cannot be done with any other WPS database that I am aware of.

To his credit, Jon Ribbens proved the veracity of these statements by tracking his own BSSID location using the Python code in that article.

==================================================================== From: Jon Ribbens <jon+ snipped-for-privacy@unequivocal.eu Newsgroups: comp.lang.python,misc.phone.mobile.iphone,comp.mobile.android,alt.internet.wireless,alt.comp.os.windows-10 Subject: Re: Apple changed their documentation at my request but it proves they don't care about privacy Date: Sun, 6 Sep 2026 00:06:34 -0000 (UTC) Message-ID: <slrn119pbka.8k8.jon+ snipped-for-privacy@raven.unequivocal.eu>

Yes, I know that too now, after reading the paper. I downloaded the code at

formatting link
(which was originally uploaded in 2015) and ran it locally with my own AP MAC address and confirmed it showed my home location very accurately.

It does concern me that there is an attack model here which is that a mildly technically-inclined stalker can very easily get the BSSID of their victim and, as you say, find out where they've gone if they move house to get away from them. ====================================================================

For others to benefit from, in my records is this initial version of apple_bssid_locator.py where when I ran it, I was horrified to find that every one of my dozens of hidden access point BSSIDs were there!

I suggest each user on this thread who wishes to better understand the nature of the problem set (as described by the paper), run this code.

#!/usr/bin/env -S uv run --script # -*- coding: utf-8 -*- # C:\app\os\python\apple_bssid_locator\apple_bssid_locator.py # Queries Apple WPS database for GPS:BSSID location pairs # Implementation based on

formatting link
# # Usage: apple_bssid_locator.py 11:22:33:AA:BB:CC # Usage: apple_bssid_locator.py 11:22:33:AA:BB:CC --all # Usage: apple_bssid_locator.py 11:22:33:AA:BB:CC --map # # Changelog: # v1p0 20251205 - Initial version from apple_bssid_locator.py # v1p1 20251214 - Added logging to results.txt # v1p2 20251215 - Timestamped results.txt to avoid overwrites # v1p3 20251219 - Limited output to 6 decimal places # v1p4 20251219 - Added raw integer output alongside converted decimals # v1p5 20251222 - Fixed raw to decimal conversion (divide by 100 Million) import argparse import requests import webbrowser import AppleWLoc_pb2 def parse_arguments(): parser = argparse.ArgumentParser() parser.add_argument("bssid", type=str, help="display the location of the bssid") parser.add_argument("-m", "--map", help="shows the location on google maps", action='store_true') parser.add_argument("-a", "--all", help="shows all results returned, not just the requested one", action='store_true') args = parser.parse_args() return args def format_bssid(bssid): return ':'.join(e.rjust(2, '0') for e in bssid.split(':')) def query_bssid(bssid, output_file="results.txt"): apple_wloc = AppleWLoc_pb2.AppleWLoc() wifi_device = apple_wloc.wifi_devices.add() wifi_device.bssid = bssid apple_wloc.unknown_value1 = 0 apple_wloc.return_single_result = 0 # request ALL results serialized_apple_wloc = apple_wloc.SerializeToString() length_serialized_apple_wloc = len(serialized_apple_wloc) headers = {'User-Agent':'locationd/1753.17 CFNetwork/889.9 Darwin/17.2.0'} data = b"\x00\x01\x00\x05"+b"en_US"+b"\x00\x13"+b"com.apple.locationd"+b"\x00\x0a"+b"8.1.12B411"+b"\x00\x00\x00\x01\x00\x00\x00"

  • bytes((length_serialized_apple_wloc,)) + serialized_apple_wloc r = requests.post('
    formatting link
    ', headers=headers, data=data) apple_wloc = AppleWLoc_pb2.AppleWLoc() apple_wloc.ParseFromString(r.content[10:]) # Build dictionary of results results = {} with open(output_file, "w") as f: for wifi_device in apple_wloc.wifi_devices: if wifi_device.HasField('location'): raw_lat = wifi_device.location.latitude raw_lon = wifi_device.location.longitude lat = raw_lat * 1e-8 lon = raw_lon * 1e-8 mac = format_bssid(wifi_device.bssid) results[mac] = (lat, lon, raw_lat, raw_lon) # Write both raw integers and converted decimals (8 decimal places) f.write(f"{mac}\t{raw_lat}\t{raw_lon}\t{lat:.8f}\t{lon:.8f}\n") print(f"Saved {len(results)} entries to {output_file}") return results def main(): args = parse_arguments() print("Searching for location of bssid: %s" % args.bssid) results = query_bssid(args.bssid) # Determine which BSSIDs to process bssids_to_process = results.keys() if args.all else [args.bssid.lower()] found = False for bssid in bssids_to_process: if bssid in results: lat, lon, raw_lat, raw_lon = results[bssid] if lat == -180.0 and lon == -180.0: continue # Skip entries that were not found if found: print() print(f"BSSID: {bssid}") print(f"Raw latitude integer: {raw_lat}") print(f"Raw longitude integer: {raw_lon}") print(f"Latitude (degrees): {lat:.8f}") print(f"Longitude (degrees): {lon:.8f}") if args.map: url = f"
    formatting link
    {lat:.8f},{lon:.8f}" webbrowser.open(url) found = True if not found: print("The bssid was not found.") if __name__ == '__main__': main() # end of C:\app\os\python\apple_bssid_locator\apple_bssid_locator.py
apple_bssid_locator.py

Usenet welcomes technical discussion of topics that are relevant to the newsgroups in which they are posted.

I don't know or care where Jon Ribbens obtained any Python code. Perhaps you provided it to him directly. It wasn't posted here.

I don't know how you misunderstood what I wrote so badly.

I haven't asked for Python code. I've observed that you haven't posted any Python code, and therefore your posts should not be in comp.lang.python. If you want to talk about Python here in comp.lang.python, that's great. If you don't, I wish you'd go away.

Are you claiming that there's Python code in that paper? There is none in the PDF. (I didn't read it in any depth because it's not something I care about.)

I see you've posted some Python source code later in this thread, along with Windows batch and PowerShell. Since you haven't said anything about the code (how it's written, what features it uses, how it could be improved), I suggest that it's (a) far too late to excuse you behavior so far, and (b) still inappropriate for comp.lang.python.

Feel free to have the last word and pretend you've won.

Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com void Void(void) { Void(); } /* The recursive call of the void */

He achieved nothing. It's all weasel words. - nothing but a vague attempt(regardless of the size of multiple missives) to sound impressive and/or meaningful without any concrete proof.

...w¡ñ§±¤ñ

Some folks in the midwest would say he has a paper ass, I guess.

(Snipping for brevity for inline replies, sorry that this removes the context, but in this case it probably is preferrable, please refer to the parent post for the full context:)

(And thanks for the post, J> The purpose of these databases of BSSID locations is to assist devices

There was already a mechanism to do this at least since "3G" using mobile data connections, right?

(I think this is one of the aspects that was made only implicit in most of the thread, and it would have helped if it was made more explicit...)

[...]

I'm leaning towards existing laws being more than sufficient, in developed countries.

Not to mention Apple is not necessarily known for allowing older systems to remain in use, so it'd be curious if they chose precisely a situation like this to behave differently.

Nuno Silva

I think that is what Maria is saying, and I have no information to the contrary.

To me it's fairly intuitive that if someone has taken the unusual step of explicitly marking their network as "hidden", then its location should not be included in these databases - especially given the fact that the "_nomap" SSID method doesn't work for "hidden" networks.

My impression is that as a result of Maria's communications with them, Apple updated their documentation to note that "hidden" networks are still listed in their database, and removed Maria's own BSSID(s) from the database.

AH! Understood.

Cheers, Carlos. ES🇪🇸, EU🇪🇺;

Yes. It was possible since GSM was invented, but somebody had to figure out that, and design a methodology. Initially, it involved a written request to the mobile network provider to do calculations using dumps of logs from each tower that could be involved.

And at some time it was automated, and phones could find their rough location instantly.

Oh, they have to support their existing supported hardware at least, and phase them out slowly. Years.

Cheers, Carlos. ES🇪🇸, EU🇪🇺;

We didn't ask to have it explained. Knowing this is not about skills, though. A mathematician can have very high skills, yet know nothing about networks. Even a skilled computer programmer may not know about them, and be a world master on IBM big iron assembler programming (and being paid handsomely - a tiny fact I happen to know) and not know offhand what the BSSID is.

No, we don't travel with our routers.

My router belongs to the ISP and I have to return it when I move, then I will get a new one at my destination. You should be intelligent enough to accept this. Maybe doesn't happen in your nook of the world, but you must understand that you are posting to an international medium.

Don't be insulting. You can say the same things without insulting people or being patronizing.

...

Ok, finally. The crux of the issue.

Cheers, Carlos. ES🇪🇸, EU🇪🇺;

But, unless I misunderstand the context, the device might not *have* a "mobile data connection". For example a SIM-less tablet/laptop/etc. might still want to determine its position.

[...]

I asked ChatGPT for more info. Take with a pinch of salt.

Q: How was it found that the location of a mobile phone (GSM) could be calculated from the data logged by nearby towers? I think it was a doctorate paper?

A: Yes — and I think I know what phenomenon you’re remembering. It wasn’t a single discovery in one doctoral thesis, but there were important early academic/industry papers and theses showing that GSM network measurements could be turned into a geographical position.

The key insight is surprisingly simple: a GSM phone is constantly measuring the surrounding base stations, not just the tower it is currently connected to. What information is available?

A GSM handset/network can provide things such as:

Cell ID — which base station/cell the phone is using. RSSI / received signal strength — how strongly it receives neighbouring cells. Timing Advance (TA) — effectively an estimate of how far the phone is from its serving base station, in discrete distance steps. Measurements from several neighbouring base stations.

If you know where the base stations are, these measurements constrain where the phone can be.

For example, if tower A gives a Timing Advance corresponding roughly to

2 km:

Phone * / \ / \ / \ / \ / ~2 km \ / \ O \ Tower A \

The phone should lie somewhere around a circle of roughly 2 km radius.

With another tower:

O Tower B / \ / \ / \ / \ / * \ ← possible position / \ / \ O---------------

Tower A

And with three or more measurements, you can narrow it down considerably. But there's an even more interesting version

You don't necessarily need an explicit distance measurement.

The phone reports the signal strengths of surrounding cells. Because radio signals generally get weaker with distance, you can construct an approximate relationship like:

signal strength → estimated distance → geographical position

This is called RSS-based positioning, and with three or more stations it can resemble trilateration.

However, radio propagation is messy — buildings, reflections, terrain, antenna patterns, etc. mean that RSS isn't a reliable direct distance measurement. That's why another approach became very important: fingerprinting.

You can drive around an area recording:

Location Cell A Cell B Cell C Cell D

--------------------------------------------------

40.123, -3.21 -55 -72 -81 -90 40.124, -3.21 -58 -69 -79 -88 40.125, -3.21 -63 -65 -76 -91 ...

Then, when an unknown phone produces:

Cell A = -60 Cell B = -67 Cell C = -77 Cell D = -89

you look for the place in the database whose "radio signature" most closely matches it.

That's GSM fingerprinting, and it's actually a very powerful idea. And your memory of a doctorate/thesis is plausible

There are quite a few doctoral works in this area.

One particularly relevant early work is Christopher Drane, Malcolm Macnaughtan and Craig Scott, “Positioning GSM Telephones,” published in IEEE Communications Magazine in 1998. Interestingly, the authors say they had achieved accurate position measurements using GSM as early as May 1996.

There is also Jian Zhu's 2006 Georgia Tech PhD dissertation, Indoor/Outdoor Location of Cellular Handsets Based on Received Signal Strength, specifically investigating handset positioning from the received signal strengths of surrounding base stations.

And a later PhD dissertation, Zaenab Shakir (Florida Institute of Technology, 2020), deals explicitly with geolocation from signal level measurements and Timing Advance inside the cellular network.

There is also a particularly interesting doctoral thesis by Lauri Wirola on the evolution of cellular positioning standards, covering methods based on cell coverage combined with time delay, time difference and received signal strength. One subtle point

If what you remember is specifically "someone discovered that you could reconstruct the location of a phone from the logs of the towers, without GPS", then I suspect you're remembering something slightly different from ordinary GSM triangulation.

There are techniques where the network's existing logs/measurements — serving cell, neighbouring-cell measurements, Timing Advance, handovers, etc. — can be accumulated over time and used to infer a person's route/location.

That gets particularly interesting because you don't need to know the phone's GPS position at all. The cellular network itself becomes a kind of enormous, distributed positioning system.

If you tell me roughly when you encountered the paper (1990s / 2000s /

2010s) or whether it was about GSM specifically, mobile-phone surveillance, or anonymised phone records, I can try to track down the exact PhD paper you're remembering.

Sources:

PPubMed Central (PMC) A Modular Localization System as a Positioning Service for Road Transport - PMC CCiteSeerX Positioning GSM Telephones GGeorgia Tech Repository Indoor/Outdoor Location of Cellular Handsets Based on Received Signal Strength SScholarship Repository "Geolocation Based on Signal Level Measurement and Time Advance Inside " by Zaenab Shakir TTampere University Research Portal Studies on location technology standards evolution in wireless networks - Tampere University Research Portal

Cheers, Carlos. ES🇪🇸, EU🇪🇺;

Hi Jon,

I appreciate your intelligence as you got everything right tactically. You even got the fact of how shocking the truth is, correct!

You said what Apple is doing is, to you, "highly implausible". I would agree, had I not been horrified to find out Apple is doing it!

The fact Apple is doing it shocked me, which is what started this quest. At that time, Apple said nothing about whether they're doing it.

But I have letters from Apple lawyers saying they will document it. And they did.

So...

It's not only not "highly implausible", but Apple now *says* they do it!

formatting link

That documentation, which I have in my email records dated months before it was documented, from Apple lawyers, saying that they'd document it, makes it pretty plausible after all.

The fact Apple documents it, when they didn't document it when I first brought this to their attention (and to that of the newsgrops), is pretty good evidence that it's not only NOT "highly implausible" but shockingly true.

The fact it's true is the shocking part. Is it not?

The great thing about Usenet is people work together to help all learn.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required