01 — Overview
Executive Summary
A vulnerability in Bird/Spin's /scan API endpoint allows systematic enumeration of micromobility vehicle fleets worldwide. By exploiting sequential hardware serial numbers, we identified 78.4% of the UC Davis campus fleet in under six hours using seven machines in parallel — bypassing all privacy protections designed into the GBFS standard.
Key finding: The /scan endpoint — designed for rider QR code scanning — accepts raw serial numbers and returns persistent vehicle identities, GPS coordinates, battery levels, and IMEI numbers. This single endpoint bypasses every privacy mechanism in the GBFS specification.
02 — Background
The Challenge — GBFS Privacy by Design
The General Bikeshare Feed Specification (GBFS) v2.3 was intentionally designed to prevent vehicle tracking. Every time a client polls the free_bike_status.json endpoint, all vehicle IDs are rotated. The specification explicitly states that persistent identity must not be derivable from public feeds.
What GBFS provides per poll:
- Temporary
bike_id — rotated every poll cycle
- GPS coordinates (real, but not linkable across polls)
- Battery level (real, but not linkable)
- Vehicle type (generic, e.g., "scooter")
On the UC Davis campus, GBFS shows 673 vehicles on any given poll — but zero are trackable across consecutive polls. Every vehicle gets a new random ID. This is the privacy guarantee that riders and regulators expect.
The question was: can persistent identity be recovered despite these protections?
03 — Discovery
Discovery Timeline
The path from zero persistent identities to 538 identified vehicles unfolded over several phases, each building on the previous.
| Phase |
Method |
Vehicles Found |
Cumulative |
Time |
| 1 |
GBFS observation |
0 (rotating IDs) |
0 |
Ongoing |
| 2 |
Physical QR scan |
19 |
19 |
3 hours |
| 3 |
Barcode brute force (9M range) |
7 |
26 |
4 hours |
| 4 |
IMEI scanning (TAC ranges) |
3 |
29 |
2 hours |
| 5 |
Serial number V1 |
+271 |
300 |
82 min |
| 6 |
Serial V2–V4 (expanded ranges) |
+140 |
440 |
48 min |
| 7 |
Multi-machine fast+sweep |
+98 |
538 |
45 min |
04 — Technical Detail
The Vulnerability — /scan Endpoint
Bird/Spin's rider app uses a /scan endpoint to resolve physical QR codes to vehicle records. This endpoint was designed for proximity-based identification but accepts raw identifiers over the network with no proximity verification.
What makes /scan dangerous:
- Accepts 4 identifier types: barcode, IMEI, serial_number, sticker_id
- Serial numbers are hardware-stamped and sequential within manufacturing batches
- Returns the persistent bird_id UUID — the master identity key
- Returns real-time GPS, battery, model, IMEI, fleet assignment
- No proximity check, no CAPTCHA, no anomaly detection on sequential scans
The serial number format follows a predictable hardware pattern:
"A1S0C2117C0378"
Request / Response:
POST /scan
Authorization: Bearer [rider_jwt_token]
Content-Type: application/json
{
"serial_number": "A1S0C2117C0378",
"mode": "rider"
}
{
"bird_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"code": "8KL9M2Z",
"serial_number": "A1S0C2117C0378",
"imei": "861234567890123",
"model": "nbmax23",
"vehicle_class": "scooter",
"fleet_id": "davis-ca",
"location": {
"latitude": 38.5382,
"longitude": -121.7617
},
"battery_level": 72,
"locked": false,
"born_at": "2024-03-15T08:22:00Z"
}
Critical: A single API call returns enough data to persistently track any vehicle — including its real-time GPS position, hardware IMEI, and manufacturing timestamp. This endpoint was never meant for bulk enumeration, but nothing prevents it.
05 — Anti-Scraping
ID Virtualization — The Anti-Scraping Layer
Bird has implemented meaningful anti-scraping protections on most endpoints. The /bird/nearby endpoint generates entirely fabricated vehicle identities per session — different IDs, codes, models, and battery ranges for every JWT token. Only GPS coordinates and approximate battery levels reflect reality.
GBFS feeds rotate all identifiers per poll. These are genuine privacy protections that work as designed.
But /scan bypasses all of it. It returns the real persistent identity — the one identifier that ties everything together.
| Endpoint |
Vehicle IDs |
GPS |
Battery |
Model |
IMEI |
Rate Limited |
/bird/nearby |
Fabricated |
Real |
Approx |
Fabricated |
N/A |
Per-token |
GBFS feeds |
Rotated |
Real |
Real |
Generic |
N/A |
Public |
/scan |
Real + Persistent |
Real |
Real |
Real |
Real |
Subnet-only |
06 — Analysis
Serial Number Analysis
Hardware serial numbers follow a structured format that reveals manufacturing batch, hardware variant, and sequential unit number. This structure is what makes enumeration possible.
A1SMaker
0CVariant
2117Batch
CSep
0378Unit
| Segment |
Values Found |
Meaning |
| Maker |
A1S, A1B, N4Z, A0S |
A1S = scooters, A1B = e-bikes, N4Z = alt scooters, A0S = nbs90l model |
| Variant |
0A–0F, 4A–4F, 5B, WE, 01 |
Hardware revision / radio configuration |
| Batch |
2040–2150+ |
Manufacturing batch (Davis fleet: 2047–2135) |
| Separator |
C |
Fixed delimiter |
| Unit |
0001–0600 |
Sequential unit within batch (variable max) |
Distribution of identified vehicles across manufacturing batches:
07 — Efficiency
The Efficiency Breakthrough
The serial number approach is 1,667 times more efficient than barcode brute force, turning a 10-day operation into an 82-minute scan.
~10 days
Barcode Brute Force
9,000,000 candidates · 0.004% hit rate
~3 days
IMEI Scanning
1,400,000 candidates · 1.9% hit rate
82 min
Serial Scanning
16,200 candidates · 10% hit rate
Why it works: Barcodes are random 7-digit codes (10M possible). IMEIs have a known TAC prefix but 7 random digits (10M per TAC). Serial numbers are structured: ~15 maker+variant combos × ~100 batches × ~600 units = ~900,000 total, and real fleets cluster in a narrow batch range, reducing the effective search space to ~16,200.
08 — Network
Rate Limiting Discovery
Rate limiting on the /scan endpoint is subnet-dependent, not account-dependent. Requests from mobile carrier networks — the same networks that scooters themselves use — experience zero throttling.
| Network Type |
Throughput |
Rate Limiting |
Notes |
| T-Mobile Cellular |
~50 req/s |
None detected |
Same CGNAT as scooter fleet |
| University Ethernet |
~10 req/s |
Moderate |
Sustained without 403s |
| Residential ISP |
~8 req/s |
Moderate |
Occasional slowdowns |
| Azure Datacenter |
~3 req/s |
Aggressive |
Frequent 403 responses |
Implication: Bird's rate limiting is designed to block datacenter scraping but trusts mobile carrier IPs — the same IPs used by millions of legitimate riders. Any attacker on cellular has effectively unlimited access.
09 — Infrastructure
Multi-Machine Architecture
Seven machines across five different network types were deployed in parallel, with results merged via shared storage and HTTP file servers.
Local Mac
UC Davis Ethernet
Primary coordinator
~10 req/s sustained
Old Mac
T-Mobile Cellular
Star performer
~50 req/s, zero throttling
Windows VM
Residential Broadband
Steady contributor
~8 req/s
Codespace #1
Azure (West US 2)
Throttled but functional
~3 req/s
Codespace #2
Azure (West US 2)
Throttled but functional
~3 req/s
Deepnote
Cloud (GCP)
Supplementary
~5 req/s
Merge Controller
Local Mac
Dedup + reconcile
OneDrive / iCloud / HTTP sync
Sync pattern: Each machine writes discovered vehicles to a local JSON file. Files sync via OneDrive, iCloud, and HTTP file servers (python3 -m http.server). The merge controller on the local Mac deduplicates by bird_id UUID and produces the canonical fleet registry.
10 — Fleet
Fleet Composition
The UC Davis campus fleet consists primarily of scooters (nbmax23 model) with a smaller contingent of e-bikes.
Total GBFS-visible fleet: 686 vehicles
11 — Privacy Impact
Data Exposed Per Vehicle
Each successful /scan response returns the following fields for a single vehicle. Combined with polling, this enables continuous real-time tracking.
Bird ID (UUID)
f47ac10b-58cc-4372-a567-0e02b2c3d479
Serial Number
A1S0C2117C0378
GPS Position
38.5382, -121.7617
Locked Status
false (available)
Born At
2024-03-15T08:22:00Z
Persistent Tracking
bird_id never rotates
Privacy implication: With a persistent bird_id, an attacker can poll GBFS feeds and correlate GPS positions over time — effectively tracking individual vehicles (and by proxy, their riders) across the city. The GBFS ID rotation is meaningless once persistent identity is known.
12 — Scale
Global Implications
This technique is not specific to UC Davis. It exploits hardware-level serial number patterns that are consistent across Bird/Spin's entire manufacturing pipeline.
- Serial numbers are sequential across manufacturing batches — not randomized per deployment
- The
/scan endpoint is globally available and core to the rider app flow
- Any city's fleet can be enumerated by scanning the relevant batch ranges
- Batch numbers correlate with deployment dates — newer cities use higher batch numbers
- No authentication upgrade stops this:
/scan must remain accessible to every rider
- Estimated global fleet exposure: millions of vehicles across hundreds of cities
200+
Cities with Bird/Spin
Hours
Per-City Enumeration Time
Millions
Vehicles Globally Exposed
13 — Visualization
Identified vs. Unknown Vehicles
Gold markers represent vehicles with confirmed persistent identity. Gray markers represent vehicles visible in GBFS but not yet linked to a hardware serial number.
-- Identified
-- Unidentified
14 — Remediation
Recommendations for Bird/Spin
-
Rate limit /scan by account, not by IP.
A single rider account has no legitimate reason to scan more than a few vehicles per hour. Account-level rate limiting at 20 scans/hour would stop enumeration without affecting normal riders.
-
Remove serial_number as an accepted scan input.
The rider app uses QR barcodes, not serial numbers. There is no user-facing reason for the API to accept hardware serials. Remove this input type entirely.
-
Add anomaly detection for sequential scanning patterns.
Legitimate riders scan one vehicle at a time. Any account scanning serial numbers in sequence (incrementing unit numbers) is clearly automated. Flag and block these patterns in real time.
-
Implement proof-of-proximity for /scan.
Require the scanning device to be within Bluetooth or GPS range of the target vehicle. The scooters already have BLE radios — use them for proximity verification before returning identity data.
-
Rotate the serial-to-barcode mapping server-side.
Even if serial numbers must be accepted for warehouse operations, the mapping from serial to bird_id should rotate periodically, breaking persistent tracking from stale scans.