WiFi promiscuous-mode detector for Flock Safety surveillance cameras
Ported to standard ESP32 hardware for maximum accessibility and cost savings.
- Solderless Build Guide - No soldering required! ($9-11 total)
- PCB Design Package - Custom board: schematic, BOM, assembly
- Detection Methods - Every detection path, with scoring and test tooling
- Changelog - What changed and why, including the root cause of each fix
- Design decisions - Why the firmware is built the way it is, and what was rejected
Configure it before you flash. The web flasher lets you choose which detections this device watches for, which of its own alerts it uses (light, sound, vibration β only what that board actually has), and two sensitivity settings. It all defaults to standard behaviour, so doing nothing changes nothing. See ADR-0001 for how it works.
This package contains everything you need to build and deploy your own Flock-You detector:
- main.cpp - Modified for ESP32 (GPIO 25, 2, 17)
- platformio.ini - ESP32 DevKit configuration
- partitions_4mb.csv - Optimized for 4MB flash
- api/ - Flask dashboard for GPS wardriving
- datasets/ - OUI lists & research data, including firmware_derived_signatures.md (the signatures extracted from a real Flock camera firmware image, with the constant that holds each one)
- pcb/ - Custom PCB design package (schematic, BOM, assembly guide)
Note: there is no published case design β see hardware/README.md for why.
- Solderless Build Guide - Assembly, testing, troubleshooting
- PCB Design Package - Schematic, BOM, assembly guide
- Detection Methods - Detection paths and confidence scoring
- Firmware-Derived Signatures - Signature provenance
- Printable Quick Start - Plain-language pocket card for non-technical users (8.5x11 sheet version)
| Build Type | Components | Total Cost | Detection Accuracy |
|---|---|---|---|
| Minimal | ESP32 + USB cable | $5 | β 100% |
| Breadboard | + Buzzer + breadboard | $9-11 | β 100% |
| OUI-SPY | Pre-built board | $85 | β 100% |
Same detection performance, 85% cost savings!
Cost: $5 | Time: 5 minutes | Difficulty: βββββ
- ESP32 DevKit + USB cable
- Onboard LED provides visual feedback
- Perfect for testing or silent operation
Cost: $9-11 | Time: 10 minutes | Difficulty: βββββ
- Add passive buzzer module + breadboard
- Audio chirps on detection
- No soldering required
- Full Guide
Minimum:
- ESP32 DevKit ($5-6)
- USB Micro cable ($1)
Recommended:
- ESP32 Breadboard Kit ($15-20)
- Includes everything: ESP32 + breadboard + jumpers + buzzer
# Install PlatformIO
pip install platformio
# Clone / enter the repo
cd flock-you-esp32
# WiFi-only (recommended first flash β works on any ESP32 DevKit)
pio run -e esp32dev -t upload && pio device monitor
# WiFi + BLE coexistence (continuous BLE scan + WiFi simultaneously)
pio run -e esp32dev-ble -t upload && pio device monitor
# M5Atom variants β use the unified flasher script
./flash.sh # interactively identifies your device
./flash.sh --once # flash one device and exitAll supported environments:
| Environment | Board | BLE |
|---|---|---|
esp32dev |
ESP32 DevKit | β |
esp32dev-ble |
ESP32 DevKit | β COEX |
m5atom-lite |
M5Atom Lite | β |
m5atom-lite-ble |
M5Atom Lite | β COEX |
m5atom-echo |
M5Atom Echo | β |
m5atom-echo-ble |
M5Atom Echo | β COEX |
m5atom-voice |
M5Atom Voice | β |
m5atom-voice-ble |
M5Atom Voice | β COEX |
m5atom-voices3r |
Atom VoiceS3R (S3) | β |
m5atom-voices3r-ble |
Atom VoiceS3R (S3) | β COEX |
lilygo-t-dongle-c5 |
LILYGO T-Dongle C5 | β |
lilygo-t-dongle-c5-ble |
LILYGO T-Dongle C5 | β NimBLE 2.x |
- Device boots with Super Mario 1-2 startup tune
- LED flashes on WiFi traffic
- Buzzer chirps on Flock camera detection
- Drive near known camera locations to verify
No camera nearby? Use the built-in beacon tester. Flash m5atom-lite-beacon
(from the web flasher, or pio run -e m5atom-lite-beacon -t upload) to a
second board and leave it powered near your detector. It broadcasts all 17
test scenarios β one per detection path, including the firmware-derived ones
(exact factory-default MAC, Flock accessory GATT service, bare-serial BLE name)
and the IE-fingerprint / test_flck cases β on a rotating schedule. Each
scenario derives its payload from fy_detect.h,
so the tester cannot drift out of sync with the detector's tables.
If a scenario is not detected, check the tester's [beacon] WARN lines
first (a driver-refused transmission looks exactly like a detector miss), then
the detector's [flockyou] stats β¦ counters from the 30 s heartbeat β they
separate "the frame never arrived" from "it arrived and failed to match". See
.clinerules/04-detection-methods.md for how to read them.
m5atom-lite-ble-selftest is the single-board alternative: it advertises the
fake Flock BLE signals to itself and picks them back up with its own coex scan.
It is a test build β never use it as a real detector.
That's it! You're detecting.
This firmware uses five research-proven techniques with a confidence score (0β100):
- Monitors 2.4 GHz management & data frames
- Four OUI confidence tiers (PR#39 + firmware-derived set):
- HIGH (33 OUIs) β exclusively Flock Safety registered β score 40, always alerts
- MFR (8 OUIs) β Liteon/USI contract manufacturer +
00:03:7fQualcomm Atheros (the camera's QCA9377 radio) β score 20, silent log only. Liteon OUIs live here rather than in HIGH (f4:6a:dd,f8:a2:d6,14:b5:cd) because Liteon silicon ships in unrelated consumer gear too. - SoundThinking (1 OUI) β acoustic sensor co-deployed with Flock β score 35, alerts
- FW-default MAC (2 full addresses) β
00:03:7f:50:00:01/00:03:7f:4f:00:16, the factory-default QCA9377 radio MACs baked into the camera firmware image β score 55, alerts. Matched byte-for-byte, because the bare00:03:7fOUI is shared with every other Atheros device on earth; only an unprovisioned unit still transmits them.
- addr1 receiver-side detection (catches sleeping cameras)
- addr3 BSSID fallback for randomized addr2 frames (now ON by default)
- Flock cameras send probe requests with empty SSID
- Combined score OUI+probe = 62 β HIGH CONFIDENCE on first match
- IE fingerprint bonus (upstream signature): the probe's Information
Elements are also walked and encoded as a signature string, compared against
the drive-tested LiteOn/USI fingerprint
2,12,127,221:506f9a16030103,45,191,221:0050f208000000(from colonelpanichacks/flock-you). A match adds +18 (62 β 80). It is additive only β never a replacement gate β so a camera on firmware we haven't fingerprinted still fires at 62. Counter:iesig=in thestats gateheartbeat line. - Field-tested: 11/12 cameras detected, only 2 false positives
- Patterns:
"Flock Camera net.","Flock-XXXXXX","FLOCK-XXXXXX","penguin","pigvision","fs ext battery","flck" "flck"covers the truncated spellingtest_flckβ the development Wi-Fi credential string Flock shipped in production Falcon/Sparrow firmware (CVE-2025-59409). It contains no"flock"substring (f-l-c-k vs f-l-o-c-k), so it needs its own keyword or such a camera is invisible to the SSID path."Flock Camera net."cameras use locally-administered MACs (OUI matching won't work)ALERT_LAA_SSIDtype detects these β SSID is the sole WiFi handle- Sequential-MAC heuristic:
:DE/:DFlast-byte pair on adjacent channels β +10 pts
- Passive NimBLE scan for Flock BLE advertisements
- Checks: mfr-ID
0x09C8(XUNTONG/Flock), Raven service UUIDs (GainSec) plus the whole Raven0x3100β0x3500service range, device names, the Flock accessory GATT service (e8ccbb38-β¦) and the Nordic legacy DFU service β plus name shapes a keyword list can't express:Penguin-NNNNNNNNNN, a bare 10-digit serial,DfuTarg - A bare "in the Raven block" match no longer alerts. Only the 5 named
Raven services may alert stand-alone; any unnamed value that merely falls
inside
0x3100β0x3500is recorded asble_raven_rangeand stays silent. That block is unassigned by the Bluetooth SIG, so any vendor may use a value in it β and a live false positive proved it: an unnamed device with a randomised MAC at β88 dBm chirped and held the LED red on the strength of nothing but being "in range". Recovered bystats ble β¦ ravenrange=. - Standard Bluetooth SIG services never alert on their own.
0x180A(Device Information),0x1809(Health Thermometer) and0x1819(Location and Navigation) appear in GainSec's Raven write-up, but they are advertised by essentially every BLE device ever made β a fitness band used to chirp as a "Raven camera" at 45 points. They are now firmware-estimation evidence only, andfyService16IsStandardSvc()blocks them even if re-added to the table. - Advertised device names are reported as
device_namein the JSON/logs - BLE_COEX_MODE=1 (default for all
-bleenvironments): ESP-IDF SW coexistence scheduler runs WiFi promiscuous + BLE simultaneously β no promiscuous pause needed- Trade-off on the
BLE_COEX_MODE=0(time-multiplexed) path: WiFi promiscuous mode is paused entirely forBLE_SCAN_DWELL_MS(5 s) of everyBLE_SCAN_INTERVAL_MS(60 s) β ~8 % of WiFi airtime is blind, and a camera seen only during that window is missed outright. The coex path removes the blackout but still misses roughly 10β20 % of frames during BLE TX/RX windows. Neither is a bug; both are a single-radio trade-off, and it is why the-bleenvironments default to coexistence.
- Trade-off on the
- 2.4 GHz only, on every board except the ESP32-C5. The ESP32, ESP32-S3 and all
M5Atom variants have 2.4 GHz-only radios:
esp_wifi_set_channel(157, β¦)returnsESP_ERR_INVALID_ARGand does nothing. Issue-#43 "Flock Camera net." cameras transmit simultaneously on 2.4 GHz ch.1 and 5 GHz ch.157, so a 2.4-only build observes only half of that camera's radios. That is a hardware limit rather than a firmware gap β thelilygo-t-dongle-c5environment (-DESP32C5_DUALBAND=1, experimental) is the dual-band answer. See the channel notes near the top ofmain.cpp. - BLE hit within 60 s of WiFi hit β +20 confidence bonus
- addr2 (transmitter) β standard detection
- addr1 (receiver) β catches cameras receiving probe responses
- addr3 (BSSID) β fallback for randomized MACs
Every detection carries a detection_method string in the serial JSON (and in
the dashboard/CSV export). The full set:
detection_method |
Protocol | Fires when | Score |
|---|---|---|---|
oui_addr2 |
wifi |
addr2 matches a high-confidence Flock OUI |
40 |
fw_default_mac |
wifi |
addr2 is an exact factory-default camera radio MAC (00:03:7f:50:00:01 / β¦:4f:00:16) β an unprovisioned unit |
55 |
oui_addr1 / oui_addr3 |
wifi |
OUI in the receiver (addr1) / BSSID (addr3) β AP-echo paths, deliberately quieter |
18 / 12 |
wildcard_probe |
wifi |
High/mfr-tier OUI + empty-SSID probe request. +18 when the probe's IEs also match the drive-tested LiteOn/USI fingerprint (62 β 80) β high-tier OUIs only, so an mfr-tier hit stays at 20 and cannot cross the chirp threshold | 62 (oui_addr2+wildcard_probe) / 20 mfr |
ssid |
wifi |
SSID keyword hit from a globally-administered MAC | 32, or 45 for exact Flock Camera net. |
laa_ssid |
wifi |
SSID keyword hit from a locally-administered MAC (issue-#43 cameras) | +12 over ssid |
oui_mfr |
wifi |
Contract-manufacturer OUI (Liteon/USI, 00:03:7f Qualcomm Atheros) β silent alone |
20 |
soundthinking |
wifi |
SoundThinking/ShotSpotter acoustic-sensor OUI | 35 |
ble_mfr_id |
ble |
BLE manufacturer data company ID 0x09C8 (XUNTONG/Flock) |
45 |
ble_name |
ble |
Device name keyword or shape match (Penguin-NNNNNNNNNN, bare 10-digit serial, FS Ext Battery, DfuTarg, β¦) |
35 |
ble_raven_uuid |
ble |
Advertised service UUID matches one of the 5 named Raven services (GainSec-documented). Standard SIG services (0x180A/0x1809/0x1819) are excluded |
45 |
ble_raven_range |
ble |
Advertised 16-bit service falls inside 0x3100β0x3500 but is not one of the named services β recorded and logged, but deliberately silent (below the chirp threshold). That block is not a Bluetooth SIG assignment, so any vendor may use a value in it |
20 |
ble_flock_gatt |
ble |
Flock accessory service e8ccbb38-β¦ or Nordic legacy DFU service |
45 |
Notes for dashboard consumers:
- BLE rows also carry
device_name(the advertised name) β WiFi rows leave it empty. protocoliswifi/ble;band(wifi_2_4ghz/wifi_5ghz) is preserved separately.- The Flask API additionally tags detections with
matched_signaturesandfirmware_sigβfirmware_sig: truemeans at least one signature from the camera-firmware image matched (seedatasets/firmware_derived_signatures.md), as opposed to a community-research OUI hit.
Confidence tiers: < 30 = LOW (log only) Β· 30β59 = PROBABLE Β· β₯ 60 = HIGH (alert)
See DETECTION_IMPROVEMENTS.md for full scoring tables and examples.
The detection pattern library (fy_detect.h) is fully tested via a host-side
Unity test suite β no ESP32 hardware needed:
cd flock-you-esp32
pio test -e native # run all 79 tests
pio test -e native -f test_ble_matching # MAC / BLE name / GATT / mfr-ID tests (41)
pio test -e native -f test_uuid_matching # Raven UUID + range / parsing / fw version (21)
pio test -e native -f test_wifi_patterns # OUI tiers / SSID keywords / IE fingerprint (17)All 79 tests pass against the current fy_detect.h / fy_confidence.h. The
test suite covers:
- All 33 high-confidence Flock OUI prefixes (case-insensitive)
- All 8 contract-manufacturer OUIs (Liteon/USI + Qualcomm Atheros
00:03:7f), including that14:b5:cdsits in the mfr tier and not in HIGH - SoundThinking OUI isolation (not in high or mfr lists)
- Firmware-default radio MACs match on all six bytes β near-misses in the
same
00:03:7fblock (β¦:50:00:02) must not match (firmware-derived set) - BLE device name substring matching (case-insensitive)
- BLE name shape matching: bare 10-digit serial,
Penguin-+ 10 digits,FS Ext Battery,DfuTarg, plus rejection of wrong digit counts / trailing junk - BLE mfr-ID
0x09C8match + rejection of the old incorrect0x05A7 - All 5 named Raven vendor 128-bit GATT service UUIDs (case-insensitive) β
the three standard SIG assignments that used to be listed (
0x180A/0x1809/0x1819) are covered by a negative test instead, because they must never alert - Raven service range
0x3100β0x3500, including0x3101/0x3102(the GPS-leaking services the named table alone missed) and out-of-range rejection - 16-bit service parsing from both UUID shapes (canonical 128-bit and
0x3101) - Flock accessory / Nordic DFU GATT UUIDs, and that the Flock accessory service is not reported as a Raven UUID
- Raven firmware version estimation from UUID categories
Super Mario Bros. World 1-2 (underground theme)
- 6 notes: C5 β C4 β A4 β A3 β G#4 β G#3
- Confirms buzzer is working
Two fast ascending beeps (2000 Hz β 2800 Hz)
- First time seeing a camera MAC
- Or camera reappears after 30+ seconds
- This is the only runtime audio alert β the firmware does not emit
any periodic/idle "still tracking" beep. Audio fires exclusively on a
genuine new-detection event (
confidence >= CHIRP_MIN_CONFIDENCE).
Onboard LED flashes on every detection
- Works even without buzzer
- Real-time detection visualization
- GPS coordinate tagging (USB puck or browser)
- Export formats: JSON, CSV, KML (Google Earth)
- Multi-device support
- Historical tracking
cd firmware/api
pip install -r requirements.txt
python flockyou.pyOpen http://localhost:5000 and select your serial port.
The lilygo-t-dongle-c5 and lilygo-t-dongle-c5-ble environments target the
LILYGO T-Dongle C5 β a USB-C dongle packing an ESP32-C5 (dual-band WiFi 6 + BT 5),
an ST7735S 80Γ160 colour TFT, and a WS2812B RGB LED.
| State | Display | RGB LED |
|---|---|---|
| Startup | Splash screen "T-Dongle C5 ready" β "Scanningβ¦" | Blue blink Γ 3, then green |
| Idle scanning | Scanning⦠· Channel & detection count |
Dim green |
| Detection (conf < 30) | Detection type (large) Β· MAC tail Β· RSSI Β· Channel Β· Confidence% | Dim green |
| Detection (conf 30β59) | Same, dark-orange background | Amber |
| Detection (conf β₯ 60) | Same, dark-red background | Red |
| Signal | GPIO |
|---|---|
| TFT SCLK | 5 |
| TFT MOSI | 6 |
| TFT CS | 4 |
| TFT DC | 2 |
| TFT RST | 3 |
| TFT Backlight | 1 |
| RGB LED (WS2812B) | 11 |
| BOOT button | 9 |
# WiFi-only (no BLE)
pio run -e lilygo-t-dongle-c5 -t upload
# WiFi + BLE (NimBLE 2.x required for ESP32-C5 BLE support)
pio run -e lilygo-t-dongle-c5-ble -t uploadNote: The T-Dongle C5 environments are marked experimental (
continue-on-errorin CI) because ESP32-C5 toolchain support is still maturing in espressif32@6.7.0.
- Channels: 1, 6, 11 (customizable) β hops every 100 ms (~300 ms full rotation)
- Channel lock: on a confident hit, holds that channel for 5 s of quiet before resuming the hop
- RSSI threshold: -95 dBm (configurable)
- Range: 50-100m typical, 300m with external antenna
- Latency: <10ms from RF frame to alert
- MCU: ESP32-WROOM-32 (dual-core 240 MHz)
- RAM: 520KB (uses ~62KB WiFi-only, ~72KB with BLE)
- Flash: 4MB (uses ~0.8MB WiFi-only, ~1.0MB with BLE)
- Power: ~180mA @ 3.3V (WiFi active)
- Battery: 6-8 hours on 3,000mAh 18650
- SPIFFS: 1MB partition
- Capacity: 200 unique detections with full metadata
- Persistence: CRC32-validated, atomic writes
- Recovery: Survives power loss mid-save
β
85% cheaper ($6 vs $85 for OUI-SPY)
β
Same detection (identical WiFi chipset)
β
More available (ESP32 everywhere, XIAO only Seeed)
β
Easier to prototype (breadboard-friendly)
β
Larger community (ESP32 has huge support)
β
Passive detection (no transmission, legal)
β
Proven accuracy (field-tested research)
β
Open source (modify freely)
β
Portable (pocket-sized)
β
Expandable (add GPS, batteries, external antenna)
- Know when you're being surveilled
- Document camera locations
- Share data with DeFlock community
- Raise awareness in your area
- Test detection algorithms
- Map surveillance infrastructure
- Contribute to open research
- Develop counter-measures
- GPS-tagged detection mapping
- Export to Google Earth (KML)
- Build community databases
- Identify high-surveillance zones
- Dashboard mount
- USB power from car
- Audio alerts while driving
- Optional battery for portability
| Part | Qty | Unit Price | Total |
|---|---|---|---|
| ESP32 DevKit | 1 | $5-6 | $5-6 |
| KY-006 Passive Buzzer | 1 | $1-2 | $1-2 |
| 400-pt Breadboard | 1 | $2 | $2 |
| Male-Male Jumpers (3) | 1 | <$1 | <$1 |
| USB Micro Cable | 1 | $1 | $1 |
| Subtotal | $9-11 |
- Check passive (not active) buzzer
- Verify GPIO 25 connection
- Try swapping buzzer polarity
- Disable in code:
#define USE_BUZZER 0
- No cameras nearby (drive to known locations)
- Check serial output (should show channel hopping)
- Lower RSSI threshold:
#define RSSI_MIN -100 - Verify WiFi promiscuous mode enabled
- Update PlatformIO:
pio upgrade - Check board definition:
esp32dev - Verify partition file exists
- Clean build:
pio run -t clean
- πΈ Share your build photos
- π Report bugs & issues
- π‘ Suggest features
- π Improve documentation
- π§ͺ Field-test and report accuracy
- πΊοΈ Submit camera locations to DeFlock
See the Apache License 2.0 and attribution notice for the project's licensing terms. Original upstream and third-party material retains its applicable license and notices.
- colonelpanichacks - Original Flock-You creator
- ΓΡΔΓΆΓΡΡΓΆΠͺΓΆΡΡΰΈ (@NitekryDPaul) - WiFi research, 30 OUIs, addr1 technique
- Michael / DeFlockJoplin - Wildcard-probe signature, 31st OUI
- Will Greenberg - BLE manufacturer ID detection
- DeFlock / FoggedLens - Crowdsourced ALPR data
- GainSec - Raven BLE service UUIDs
- Modified for standard ESP32 (4MB flash, UART)
- Solderless assembly guide
- Business analysis & documentation
- Community testing & feedback
- Passively receives publicly-broadcast WiFi frames
- Does not transmit any signals
- Does not authenticate to networks
- Does not decrypt any data
- Educational/research purposes
- Passive WiFi reception is legal in most jurisdictions
- Equivalent to listening to public radio broadcasts
- No different from WiFi analyzers or network sniffers
- Always comply with local laws
- Respect privacy and property rights
- Use for legitimate security research
- Contribute findings to public good (DeFlock)
- Don't use to enable illegal activity
The authors assume no liability for misuse.
- Original Repo: colonelpanichacks/flock-you
- De-Flock: deflock.me - Crowdsourced camera maps
- Research:
firmware/datasets/- Full methodology
- ESP32: espressif.com
- PlatformIO: platformio.org
- WiFi Sniffing: ESP32 Promiscuous Mode
- Privacy Tech: EFF Surveillance Self-Defense
- Hardware Cost: $5-11 (vs $85 OUI-SPY)
- Build Time: 5-10 minutes
- Detection Accuracy: Same as premium hardware
- Supported Boards: Any ESP32 with 4MB+ flash
- Community: Growing!
You're 2 steps away from detecting surveillance:
- Buy hardware β $5-11
- Flash the firmware β 10 minutes (commands under Quick Start above)
Questions? Check the docs or open an issue!
Ready? Start Building β
Built with love for privacy, security, and open knowledge.
Detect. Document. DeFlock.