# bolt-network-check.ps1 - watch every network connection Bolt makes, and name it. # # Sparcle publishes a list of what Bolt contacts (https://sparcle.app/trust/network-allowlist/). # This script does not ask you to believe that list. It samples the real TCP connections held by # Bolt's own processes on this machine and prints them, classified against the published list. # # It is read-only. It changes nothing, installs nothing, and uploads nothing. The only network # traffic it can generate is reverse-DNS lookups to name what it finds; -NoDns turns that off. # # powershell -ExecutionPolicy Bypass -File bolt-network-check.ps1 # powershell -ExecutionPolicy Bypass -File bolt-network-check.ps1 -Duration 300 # # macOS and Linux: https://sparcle.app/scripts/bolt-network-check.sh param( [int]$Duration = 60, [int]$Interval = 2, [switch]$NoDns ) $boltNames = @('bolt', 'bolt-api', 'Bolt', 'postgres') function Get-BoltProcessIds { Get-Process -ErrorAction SilentlyContinue | Where-Object { $boltNames -contains $_.ProcessName } | Select-Object -ExpandProperty Id } function Get-Classification($name) { switch -Wildcard ($name) { '*github.com' { return 'Update check. The updater fetches a release manifest from GitHub. No Sparcle server is involved.' } '*githubusercontent.com' { return 'Update download from GitHub.' } '*sparcle.app' { return 'Sparcle. Bolt does not need us at runtime, so this is worth a look. Tell us at security@sparcle.app.' } '*1e100.net' { return 'Google, direct from this machine. Present only if you connected a Google account.' } '*google*' { return 'Google, direct from this machine. Present only if you connected a Google account.' } '*microsoft*' { return 'Microsoft 365, direct from this machine. Present only if you connected a Microsoft account.' } '*office*' { return 'Microsoft 365, direct from this machine. Present only if you connected a Microsoft account.' } '*huggingface*' { return 'Hugging Face. A one-time download of an open model you enabled. It runs on-device afterwards.' } '*anthropic.com' { return 'The LLM provider you configured. Bolt ships no default endpoint.' } '*openai*' { return 'The LLM provider you configured. Bolt ships no default endpoint.' } '20.190.*' { return 'Microsoft address block. Present only if you connected a Microsoft account.' } '13.107.*' { return 'Microsoft address block. Present only if you connected a Microsoft account.' } '142.25*' { return 'Google address block. Present only if you connected a Google account.' } '172.217.*' { return 'Google address block. Present only if you connected a Google account.' } '140.82.*' { return 'GitHub address block. This is the update check.' } '185.199.*' { return 'GitHub address block. This is the update check.' } default { return "Not named by reverse DNS, and not in a block we recognise. Identify it with: Resolve-DnsName $name" } } } $pids = Get-BoltProcessIds if (-not $pids) { Write-Host 'Bolt does not appear to be running. Start it, then run this again.' exit 1 } Write-Host "Watching Bolt for $Duration seconds. Use Bolt normally while this runs; the more you do, the better the test." Write-Host "Processes: $($pids -join ', ')" Write-Host '' $remote = @{} $local = @{} $elapsed = 0 while ($elapsed -lt $Duration) { foreach ($conn in Get-NetTCPConnection -ErrorAction SilentlyContinue) { if ($pids -notcontains $conn.OwningProcess) { continue } $addr = $conn.RemoteAddress if ($addr -eq '127.0.0.1' -or $addr -eq '::1' -or $addr -eq '0.0.0.0' -or $addr -eq '::') { $local["$($conn.LocalAddress):$($conn.LocalPort)"] = $true } else { $remote[$addr] = $true } } Start-Sleep -Seconds $Interval $elapsed += $Interval Write-Host -NoNewline '.' } Write-Host '' Write-Host '' Write-Host '=== Connections that left this machine ===' if ($remote.Count -eq 0) { Write-Host "None. Over $Duration seconds, Bolt's processes opened no connection to anything outside this machine." } else { foreach ($addr in $remote.Keys | Sort-Object) { $name = $addr if (-not $NoDns) { try { $ptr = Resolve-DnsName -Name $addr -Type PTR -ErrorAction Stop | Select-Object -First 1 if ($ptr.NameHost) { $name = $ptr.NameHost } } catch { } } Write-Host (' {0,-45} {1}' -f $name, (Get-Classification $name)) } } Write-Host '' Write-Host '=== What stayed on this machine ===' Write-Host " Bolt runs its own API and its own database on loopback. This is where your data actually is." foreach ($l in $local.Keys | Sort-Object) { Write-Host " $l" } Write-Host '' Write-Host 'Published list of what Bolt contacts: https://sparcle.app/trust/network-allowlist/' Write-Host 'Anything that leaves and does not match that list is something we failed to disclose. Tell us at security@sparcle.app.'